home *** CD-ROM | disk | FTP | other *** search
/ Aminet 41 / Aminet 41 (2001)(Schatztruhe)[!][Feb 2001].iso / Aminet / comm / tcp / samba_2.0.7.lha / source / amiga / amiga.c < prev    next >
C/C++ Source or Header  |  2000-12-25  |  165KB  |  8,329 lines

  1. /*
  2.  * $Id: amiga.c 1.16 2000/12/25 11:41:23 olsen Exp olsen $
  3.  *
  4.  * :ts=4
  5.  *
  6.  * AmigaOS wrapper routines for Samba 2.0.0, using the AmiTCP V3 API
  7.  * and the SAS/C V6.58 compiler.
  8.  *
  9.  * Copyright (C) 1999-2000 by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. /******************************************************************************/
  27.  
  28. #include <bsdsocket/socketbasetags.h>
  29. #include <libraries/usergroup.h>
  30.  
  31. #include <intuition/intuition.h>
  32. #include <libraries/locale.h>
  33. #include <exec/execbase.h>
  34. #include <exec/memory.h>
  35. #include <dos/dosextens.h>
  36. #include <dos/dostags.h>
  37. #include <dos/rdargs.h>
  38. #include <devices/timer.h>
  39. #include <utility/date.h>
  40.  
  41. #include <clib/usergroup_protos.h>
  42. #include <clib/socket_protos.h>
  43.  
  44. #include <clib/intuition_protos.h>
  45. #include <clib/utility_protos.h>
  46. #include <clib/locale_protos.h>
  47. #include <clib/timer_protos.h>
  48. #include <clib/alib_protos.h>
  49. #include <clib/exec_protos.h>
  50. #include <clib/dos_protos.h>
  51.  
  52. #include <sys/socket.h>
  53. #include <sys/ioctl.h>
  54. #include <sys/time.h>
  55. #include <sys/dir.h>
  56.  
  57. #include <net/if.h>
  58.  
  59. #include <constructor.h>
  60. #include <stdarg.h>
  61. #include <stdlib.h>
  62. #include <string.h>
  63. #include <unistd.h>
  64. #include <signal.h>
  65. #include <utime.h>
  66. #include <errno.h>
  67. #include <stdio.h>
  68. #include <fcntl.h>
  69. #include <inetd.h>
  70. #include <stat.h>
  71. #include <ios1.h>
  72. #include <dos.h>
  73.  
  74. #include <pragmas/usergroup_pragmas.h>
  75. #include <pragmas/socket_pragmas.h>
  76.  
  77. #include <pragmas/exec_sysbase_pragmas.h>
  78. #include <pragmas/intuition_pragmas.h>
  79. #include <pragmas/utility_pragmas.h>
  80. #include <pragmas/locale_pragmas.h>
  81. #include <pragmas/timer_pragmas.h>
  82. #include <pragmas/dos_pragmas.h>
  83.  
  84. /******************************************************************************/
  85.  
  86. /* This is for the "iface_struct" definition. */
  87. #include "interfaces.h"
  88.  
  89. /******************************************************************************/
  90.  
  91. /*#define DEBUG*/
  92. #include "Assert.h"
  93.  
  94. /******************************************************************************/
  95.  
  96. STATIC VOID ReportProblem(const char *fmt, ...);
  97. STATIC VOID ForbidDOSCleanup(VOID);
  98. STATIC VOID PermitDOS(VOID);
  99. STATIC VOID ForbidDOS(VOID);
  100. STATIC VOID UnblockDescriptorCleanup(VOID);
  101. STATIC BOOL IsDescriptorNonblocking(int fd);
  102. STATIC VOID BlockDescriptor(int fd);
  103. STATIC VOID UnblockDescriptor(int fd);
  104. STATIC VOID SaveDescriptorCleanup(VOID);
  105. STATIC VOID RestoreDescriptor(struct UFB *ufb);
  106. STATIC BOOL SaveDescriptor(struct UFB *ufb);
  107. STATIC VOID UnmangleName(char **namePtr, struct MangleInfo *mi);
  108. STATIC int MangleName(char ** namePtr,struct MangleInfo * mi);
  109. STATIC VOID CloseUnlinkUnlockCleanup(VOID);
  110. STATIC VOID OpenDirCleanup(VOID);
  111. STATIC int TranslateRelativePath(char **namePtr, char *replace, int maxReplaceLen);
  112. STATIC VOID MapDescriptorSets(const fd_set *input_fds, int num_input_fds, fd_set *socket_fds, int *max_socket_fd_ptr, fd_set *file_fds, int *max_file_fd_ptr);
  113. STATIC VOID RemapDescriptorSets(const fd_set *socket_fds, int max_socket_fd, const fd_set *file_fds, int max_file_fd, fd_set *output_fds, int num_output_fds);
  114. STATIC VOID ConvertFileInfoToStat(struct MsgPort *port, struct FileInfoBlock *fib, struct stat *st);
  115. STATIC BOOL do_match(STRPTR str, STRPTR regexp);
  116. STATIC VOID nstrcpy_blank(const size_t maxSize, char *to, const char *from);
  117. STATIC BOOL SetFileSocket(FILE *stream, int sockfd);
  118. STATIC VOID DaemonInit(VOID);
  119. STATIC struct tm *ConvertTime(ULONG seconds);
  120. STATIC VOID MapIoErrToErrno(VOID);
  121. STATIC int MapFileNameAmigaToUnix(const char *amiga, char *unix, int maxUnixLen);
  122. STATIC VOID FlushSTDOUT(VOID);
  123. STATIC VOID CleanupSambaSemaphore(VOID);
  124. STATIC BOOL SetupSambaSemaphore(VOID);
  125. STATIC VOID RemoveLockedRegionNode(struct UFB *ufb, LONG start, LONG stop);
  126. STATIC VOID DeleteLockedRegionNode(struct LockedRegionNode *lrn);
  127. STATIC LONG CreateLockedRegionNode(struct LockedRegionNode **resultPtr);
  128. STATIC VOID DeleteFileLockNode(struct FileLockNode *fln);
  129. STATIC LONG CreateFileLockNode(struct UFB *ufb, struct FileLockNode **resultPtr);
  130. STATIC LONG FindFileLockNodeByFileHandle(BPTR fileHandle, struct FileLockNode **resultPtr);
  131. STATIC VOID FindFileLockNodeByDrawerAndName(BPTR parentDir, STRPTR fileName, struct FileLockNode **resultPtr);
  132. STATIC VOID CleanupFileLocks(int fd);
  133. STATIC int HandleFileLocking(int cmd, struct flock *l, struct UFB *ufb);
  134. STATIC struct LockedRegionNode *FindCollidingRegion(struct FileLockNode *fln, LONG start, LONG stop, BOOL shared);
  135.  
  136. /******************************************************************************/
  137.  
  138. int amiga_sigmask(int signum);
  139. int amiga_sigblock(int sigmask);
  140. int amiga_sigsetmask(int sigmask);
  141. int amiga_unlink(char *name);
  142. int amiga_open(char *name, int mode, int prot);
  143. int amiga_chdir(char *path);
  144. DIR *amiga_opendir(char *dirName);
  145. VOID amiga_closedir(DIR *dir);
  146. struct dirent *amiga_readdir(DIR *dir);
  147. int amiga_mkdir(char *name, int mode);
  148. int amiga_rmdir(char *name);
  149. int amiga_creat(char *name, int prot);
  150. FILE *amiga_fopen(char *name, char *mode);
  151. int amiga_rename(char *old, char *new);
  152. char *amiga_getcwd(char *buf, size_t size);
  153. int amiga_ftruncate(int fd, off_t size);
  154. int amiga_accept(int sockfd, struct sockaddr *cliaddr, int *addrlen);
  155. int amiga_bind(int sockfd, struct sockaddr *name, int namelen);
  156. int amiga_close(int fd);
  157. int amiga_connect(int sockfd, struct sockaddr *name, int namelen);
  158. int amiga_getpeername(int sockfd, struct sockaddr *name, int *namelen);
  159. int amiga_getsockopt(int sockfd, int level, int optname, VOID *optval, int *optlen);
  160. int amiga_ioctl(int fd, unsigned long request, char *arg);
  161. int amiga_listen(int sockfd, int backlog);
  162. int amiga_read(int fd, VOID *data, unsigned int size);
  163. int amiga_recvfrom(int sockfd, VOID *buff, int len, int flags, struct sockaddr *from, int *fromlen);
  164. int amiga_select(int num_fds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, struct timeval *timeout);
  165. int amiga_sendto(int sockfd, VOID *buff, int len, int flags, struct sockaddr *to, int tolen);
  166. int amiga_setsockopt(int sockfd, int level, int optname, VOID *optval, int optlen);
  167. int amiga_socket(int domain, int type, int protocol);
  168. int amiga_write(int fd, VOID *data, unsigned int size);
  169. int amiga_stat(char *name, struct stat *st);
  170. int amiga_lstat(char *name, struct stat *statstruct);
  171. int amiga_fstat(int fd, struct stat *st);
  172. int amiga_chmod(char *name, int mode);
  173. int amiga_dup(int fd);
  174. int amiga_dup2(int old_fd, int new_fd);
  175. int amiga_chown(char *name, uid_t uid, gid_t gid);
  176. int amiga_setegid(gid_t g);
  177. int amiga_seteuid(uid_t u);
  178. int amiga_gettimeofday(struct timeval *tv);
  179. int amiga_utime(char *name, struct utimbuf *time);
  180. VOID amiga_sleep(unsigned int seconds);
  181. char *amiga_crypt(char *key, char *salt);
  182. char *amiga_getpass(char *prompt);
  183. int amiga_setgid(gid_t id);
  184. int amiga_setgroups(int ngroups, gid_t *groups);
  185. gid_t amiga_getgid(VOID);
  186. struct group *amiga_getgrgid(gid_t gid);
  187. struct group *amiga_getgrnam(char *name);
  188. int amiga_getgroups(int ngroups, gid_t *groups);
  189. struct hostent *amiga_gethostbyaddr(char *addr, int len, int type);
  190. struct hostent *amiga_gethostbyname(char *name);
  191. struct netent *amiga_getnetbyname(char *name);
  192. int amiga_gethostname(char *hostname, int size);
  193. struct passwd *amiga_getpwnam(char *name);
  194. struct passwd *amiga_getpwuid(uid_t uid);
  195. uid_t amiga_getuid(VOID);
  196. gid_t amiga_getegid(VOID);
  197. uid_t amiga_geteuid(VOID);
  198. int amiga_initgroups(char *name, gid_t basegroup);
  199. int amiga_setuid(uid_t id);
  200. int amiga_umask(int mask);
  201. unsigned long amiga_inet_addr(char *addr);
  202. char *amiga_inet_ntoa(struct in_addr in);
  203. int amiga_getopt(int argc, char *argv[], char *opts);
  204. int amiga_system(char *cmd);
  205. int amiga_fork(VOID);
  206. VOID __tzset(VOID);
  207. time_t time(time_t *timeptr);
  208. struct tm *gmtime(const time_t *t);
  209. struct tm *localtime(const time_t *t);
  210. int amiga_strcasecmp(char *a, char *b);
  211. int amiga_strncasecmp(char *a, char *b, int len);
  212. VOID (*amiga_signal(int which,VOID (* action)(int)))(int);
  213. VOID amiga_alarm(int seconds);
  214. int amiga_waitpid(pid_t pid, int *status, int options);
  215. long amiga_setsid(VOID);
  216. int amiga_setreuid(uid_t real, uid_t eff);
  217. int amiga_setregid(gid_t real, gid_t eff);
  218. int amiga_fcntl(int fd, int cmd, unsigned long arg);
  219. int amiga_getsockname(int sockfd, struct sockaddr *name, int *namelen);
  220. int amiga_statfs(char *name, struct statfs *f);
  221. int amiga_execl(char *path, char *arg, ...);
  222. char *amiga_strerror(int error);
  223. int amiga_access(char *name, int modes);
  224. off_t amiga_lseek(int fd, off_t offset, int mode);
  225. int amiga_chroot(char *name);
  226. int amiga_kill(pid_t pid, int sig);
  227. pid_t amiga_getpid(VOID);
  228. int amiga_fgetc(FILE *in);
  229. char *amiga_fgets(char *str, int n, FILE *in);
  230. int amiga_fputs(const char *str, FILE *out);
  231. int amiga_puts(const char *str);
  232. int amiga_vfprintf(FILE *out, const char *fmt, va_list args);
  233. int amiga_fprintf(FILE *out, const char *fmt, ...);
  234. int amiga_printf(const char *fmt, ...);
  235. size_t amiga_fwrite(const void *data, size_t blockSize, size_t numBlocks, FILE *out);
  236. size_t amiga_fread(void *data, size_t blockSize, size_t numBlocks, FILE *in);
  237. int amiga_fclose(FILE *stream);
  238. int amiga_fflush(FILE *stream);
  239. int amiga_fseek(FILE *stream, long int offset, int mode);
  240. long int amiga_ftell(FILE *stream);
  241. int amiga_setvbuf(FILE *fp, char *buff, int type, size_t size);
  242. int amiga_fputc(int c,FILE *stream);
  243. VOID amiga_setbuf(FILE *stream,char *buffer);
  244.  
  245. /******************************************************************************/
  246.  
  247. VOID __regargs __chkabort(VOID);
  248. VOID _CXOVF(VOID);
  249. VOID __regargs _CXBRK(VOID);
  250.  
  251. /******************************************************************************/
  252.  
  253. /* These are in the Samba runtime library. */
  254. extern int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
  255. extern int snprintf (char *str, size_t count, const char *fmt, ...);
  256.  
  257. /******************************************************************************/
  258.  
  259. #define ZERO    ((BPTR)0L)
  260. #define ERROR    (-1)
  261. #define OK        (0)
  262. #define SAME    (0)
  263. #define NO        !
  264. #define NOT        !
  265. #define DONT    !
  266. #define CANNOT    !
  267. #define BUSY    (NULL)
  268. #define NO_FLAG    (0)
  269.  
  270. /******************************************************************************/
  271.  
  272. #define FLAG_IS_SET(v,f)    (((v) & (f)) == (f))
  273. #define FLAG_IS_CLEAR(v,f)    (((v) & (f)) == 0)
  274.  
  275. #define SET_FLAG(v,f)        (v |=  (f))
  276. #define CLEAR_FLAG(v,f)        (v &= ~(f))
  277.  
  278. /******************************************************************************/
  279.  
  280. #define STRING_IS_EMPTY(s)    (s[0] == '\0')
  281. #define NUM_ENTRIES(t)        (sizeof(t) / sizeof(t[0]))
  282.  
  283. /******************************************************************************/
  284.  
  285. #define FIB_IS_FILE(fib)    ((fib)->fib_DirEntryType < 0)
  286. #define FIB_IS_DRAWER(fib)    ((fib)->fib_DirEntryType >= 0 && \
  287.                              (fib)->fib_DirEntryType != ST_SOFTLINK)
  288.  
  289. /******************************************************************************/
  290.  
  291. /* This macro lets us long-align structures on the stack */
  292. #define D_S(type,name) \
  293.     char a_##name[sizeof(type)+3]; \
  294.     type *name = (type *)((LONG)(a_##name+3) & ~3)
  295.  
  296. /******************************************************************************/
  297.  
  298. #define UFB_IS_SOCKET        0x0800
  299. #define UFB_IS_NON_BLOCKING    0x1000
  300. #define UFB_UNLINK            0x2000
  301. #define UFB_LOCKED            0x4000
  302.  
  303. #define UNIX_TIME_OFFSET    252482400
  304.  
  305. #define MAX_BSTR_LEN        256
  306. #define MAX_FILENAME_LEN    512
  307. #define MAX_FFS_NAME_LEN    30
  308.  
  309. /******************************************************************************/
  310.  
  311. /* This is for ReadArgs(), to make the parameters a little more readable. */
  312. typedef unsigned char *    KEY;
  313. typedef long            SWITCH;
  314. typedef long *            NUMBER;
  315.  
  316. /******************************************************************************/
  317.  
  318. long __oslibversion = 37;
  319.  
  320. /******************************************************************************/
  321.  
  322. extern struct Library * SysBase;
  323. extern struct Library * DOSBase;
  324. extern struct Library * UtilityBase;
  325.  
  326. /******************************************************************************/
  327.  
  328. STATIC struct Device * TimerBase;
  329. STATIC struct MsgPort * TimerPort;
  330. STATIC struct timerequest * TimerRequest;
  331. STATIC LONG MinutesWest;
  332.  
  333. /******************************************************************************/
  334.  
  335. STATIC struct Library * SocketBase;
  336. STATIC struct Library * UserGroupBase;
  337.  
  338. /******************************************************************************/
  339.  
  340. /* Activate root mode, i.e. make getuid(), etc. return 0 instead of
  341.  * the 'real' user id.
  342.  */
  343. STATIC BOOL RootMode = FALSE;
  344.  
  345. /******************************************************************************/
  346.  
  347. #if defined(_M68020) && defined(_M68881)
  348. #define MACHINE_TYPE "['020+FPU]"
  349. #elif defined(_M68020)
  350. #define MACHINE_TYPE "['020]"
  351. #else
  352. #define MACHINE_TYPE "[68k]"
  353. #endif
  354.  
  355. /******************************************************************************/
  356.  
  357. #include "Amiga_Samba_rev.h"
  358. char * VersionTag = VERSTAG " " MACHINE_TYPE " Samba version 2.0.0 ported by Olaf `Olsen' Barthel <olsen@sourcery.han.de>";
  359.  
  360. /******************************************************************************/
  361.  
  362. /* This is for backwards compatibility with Kickstart 2.04 and
  363.  * avoids a deadlock when trying to get a shared lock on
  364.  * a semaphore already held in exclusive mode by the same Task.
  365.  */
  366. STATIC VOID
  367. SafeObtainSemaphoreShared(struct SignalSemaphore * semaphore)
  368. {
  369.     /* Do it right with Kickstart 3.x. */
  370.     if(SysBase->lib_Version >= 39)
  371.     {
  372.         ObtainSemaphoreShared(semaphore);
  373.     }
  374.     else
  375.     {
  376.         /* Try to get the shared semaphore */
  377.         if(CANNOT AttemptSemaphoreShared(semaphore))
  378.         {
  379.             /* Check if we can get the exclusive version */
  380.             if(CANNOT AttemptSemaphore(semaphore))
  381.             {
  382.                 /* Oh well, wait for the shared lock */
  383.                 ObtainSemaphoreShared(semaphore);
  384.             }
  385.         }
  386.     }
  387. }
  388.  
  389. /******************************************************************************/
  390.  
  391. STATIC BOOL AllowBreak = TRUE;
  392.  
  393. STATIC BOOL
  394. CheckAbort(VOID)
  395. {
  396.     BOOL result;
  397.  
  398.     result = (BOOL)(AllowBreak && FLAG_IS_SET(SetSignal(0,SIGBREAKF_CTRL_C),SIGBREAKF_CTRL_C));
  399.  
  400.     return(result);
  401. }
  402.  
  403. VOID __regargs
  404. __chkabort(VOID)
  405. {
  406.     if(CheckAbort())
  407.         raise(SIGINT);
  408. }
  409.  
  410. int
  411. amiga_sigmask(int signum)
  412. {
  413.     int result = 0;
  414.  
  415.     ENTER();
  416.  
  417.     SHOWVALUE(signum);
  418.  
  419.     if(signum == SIGTERM || signum == SIGINT)
  420.         result = (1<<SIGINT);
  421.  
  422.     RETURN(result);
  423.     return(result);
  424. }
  425.  
  426. int
  427. amiga_sigblock(int sigmask)
  428. {
  429.     BOOL oldAllowBreak = AllowBreak;
  430.     int result = 0;
  431.  
  432.     ENTER();
  433.  
  434.     SHOWVALUE(sigmask);
  435.  
  436.     if(DONT AllowBreak)
  437.         result = (1<<SIGINT);
  438.  
  439.     if(FLAG_IS_SET(sigmask,(1<<SIGINT)))
  440.     {
  441.         AllowBreak = FALSE;
  442.  
  443.         if(oldAllowBreak != AllowBreak)
  444.         {
  445.             SocketBaseTags(
  446.                 SBTM_SETVAL(SBTC_BREAKMASK),NO_FLAG,
  447.             TAG_END);
  448.         }
  449.     }
  450.  
  451.     RETURN(result);
  452.     return(result);
  453. }
  454.  
  455. int
  456. amiga_sigsetmask(int sigmask)
  457. {
  458.     BOOL oldAllowBreak = AllowBreak;
  459.     int result = 0;
  460.  
  461.     ENTER();
  462.  
  463.     SHOWVALUE(sigmask);
  464.  
  465.     AllowBreak = FLAG_IS_CLEAR(sigmask,(1<<SIGINT));
  466.     if(oldAllowBreak != AllowBreak)
  467.     {
  468.         ULONG mask;
  469.  
  470.         if(AllowBreak)
  471.             mask = SIGBREAKF_CTRL_C;
  472.         else
  473.             mask = NO_FLAG;
  474.  
  475.         SocketBaseTags(
  476.             SBTM_SETVAL(SBTC_BREAKMASK),mask,
  477.         TAG_END);
  478.     }
  479.  
  480.     RETURN(result);
  481.     return(result);
  482. }
  483.  
  484. /******************************************************************************/
  485.  
  486. STATIC VOID
  487. ReportProblem(const char *fmt,...)
  488. {
  489.     extern const STRPTR _ProgramName;
  490.     BOOL useRequester = TRUE;
  491.     va_list varArgs;
  492.  
  493.     ASSERT(fmt != NULL);
  494.  
  495.     va_start(varArgs,fmt);
  496.  
  497.     /* Launched from Workbench? */
  498.     if(WBenchMsg == NULL)
  499.     {
  500.         if(DOSBase->lib_Version >= 37)
  501.         {
  502.             BPTR stream;
  503.  
  504.             /* Make a copy of the current terminal
  505.              * output stream. This avoids sending
  506.              * an error message through a redirected
  507.              * standard output stream, the output
  508.              * will go straight to the terminal.
  509.              */
  510.             stream = Open("CONSOLE:",MODE_NEWFILE);
  511.             if(stream != ZERO)
  512.             {
  513.                 struct FileHandle * fh = BADDR(stream);
  514.  
  515.                 /* Check if the output was redirected
  516.                  * to "NIL:"; if not, print the error
  517.                  * error message.
  518.                  */
  519.                 if(fh->fh_Type != NULL)
  520.                 {
  521.                     FPrintf(stream,"%s: ",_ProgramName);
  522.                     VFPrintf(stream,(STRPTR)fmt,(APTR)varArgs);
  523.                     FPrintf(stream,"\a\n");
  524.  
  525.                     useRequester = FALSE;
  526.                 }
  527.  
  528.                 Close(stream);
  529.             }
  530.         }
  531.     }
  532.  
  533.     /* Oh well, don't use the Shell for output. Put up a
  534.      * requester.
  535.      */
  536.     if(useRequester)
  537.     {
  538.         struct Library * IntuitionBase;
  539.  
  540.         IntuitionBase = OpenLibrary("intuition.library",37);
  541.         if(IntuitionBase != NULL)
  542.         {
  543.             struct Window * reqWindow;
  544.             struct EasyStruct es;
  545.             char title[100];
  546.  
  547.             snprintf(title,sizeof(title)-1,"Amiga Samba Error (%s)",FilePart(_ProgramName));
  548.             title[sizeof(title)-1] = '\0';
  549.  
  550.             memset(&es,0,sizeof(es));
  551.  
  552.             es.es_StructSize    = sizeof(es);
  553.             es.es_Title            = (STRPTR)title;
  554.             es.es_TextFormat    = (STRPTR)fmt;
  555.             es.es_GadgetFormat    = "Ok";
  556.  
  557.             reqWindow = BuildEasyRequestArgs(NULL,&es,0,(APTR)varArgs);
  558.             if(reqWindow != NULL && reqWindow != (struct Window *)1)
  559.             {
  560.                 struct timerequest * timeRequest = NULL;
  561.                 struct MsgPort * timePort;
  562.                 BOOL timerOpen = FALSE;
  563.                 ULONG windowSignal;
  564.                 ULONG timerSignal;
  565.                 ULONG signals;
  566.                 BOOL done;
  567.  
  568.                 timePort = CreateMsgPort();
  569.                 if(timePort != NULL)
  570.                 {
  571.                     timeRequest = CreateIORequest(timePort,sizeof(*timeRequest));
  572.                     if(timeRequest != NULL)
  573.                     {
  574.                         if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)timeRequest,0) == OK)
  575.                             timerOpen = TRUE;
  576.                     }
  577.                 }
  578.  
  579.                 windowSignal = (1UL << reqWindow->UserPort->mp_SigBit);
  580.  
  581.                 if(timerOpen)
  582.                 {
  583.                     timerSignal = (1UL << timePort->mp_SigBit);
  584.  
  585.                     timeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  586.                     timeRequest->tr_time.tv_secs    = 30;
  587.                     timeRequest->tr_time.tv_micro    = 0;
  588.  
  589.                     SendIO((struct IORequest *)timeRequest);
  590.                 }
  591.                 else
  592.                 {
  593.                     timerSignal = 0;
  594.                 }
  595.  
  596.                 DisplayBeep(reqWindow->WScreen);
  597.  
  598.                 done = FALSE;
  599.                 do
  600.                 {
  601.                     signals = Wait(windowSignal | timerSignal);
  602.  
  603.                     if(FLAG_IS_SET(signals,windowSignal))
  604.                     {
  605.                         if(SysReqHandler(reqWindow,NULL,FALSE) >= 0)
  606.                             done = TRUE;
  607.                     }
  608.  
  609.                     if(FLAG_IS_SET(signals,timerSignal))
  610.                     {
  611.                         done = TRUE;
  612.                     }
  613.                 }
  614.                 while(NOT done);
  615.  
  616.                 if(timerOpen)
  617.                 {
  618.                     if(CheckIO((struct IORequest *)timeRequest) == BUSY)
  619.                         AbortIO((struct IORequest *)timeRequest);
  620.  
  621.                     WaitIO((struct IORequest *)timeRequest);
  622.  
  623.                     CloseDevice((struct IORequest *)timeRequest);
  624.                 }
  625.  
  626.                 DeleteIORequest((struct IORequest *)timeRequest);
  627.                 DeleteMsgPort(timePort);
  628.  
  629.                 FreeSysRequest(reqWindow);
  630.             }
  631.  
  632.             CloseLibrary(IntuitionBase);
  633.         }
  634.     }
  635.  
  636.     va_end(varArgs);
  637. }
  638.  
  639. /******************************************************************************/
  640.  
  641. STATIC APTR OldWindowPtr;
  642. STATIC LONG ForbidCount;
  643.  
  644. STATIC VOID
  645. ForbidDOSCleanup(VOID)
  646. {
  647.     if(ForbidCount > 0)
  648.     {
  649.         struct Process * pr = (struct Process *)FindTask(NULL);
  650.  
  651.         pr->pr_WindowPtr = OldWindowPtr;
  652.  
  653.         ForbidCount = 0;
  654.     }
  655. }
  656.  
  657. STATIC VOID
  658. PermitDOS(VOID)
  659. {
  660.     ASSERT(ForbidCount > 0);
  661.  
  662.     if(--ForbidCount == 0)
  663.     {
  664.         struct Process * pr = (struct Process *)FindTask(NULL);
  665.  
  666.         pr->pr_WindowPtr = OldWindowPtr;
  667.     }
  668. }
  669.  
  670. STATIC VOID
  671. ForbidDOS(VOID)
  672. {
  673.     if(ForbidCount++ == 0)
  674.     {
  675.         struct Process * pr = (struct Process *)FindTask(NULL);
  676.  
  677.         OldWindowPtr = pr->pr_WindowPtr;
  678.         pr->pr_WindowPtr = (APTR)-1;
  679.     }
  680. }
  681.  
  682. /******************************************************************************/
  683.  
  684. #define SINGLE_CHARACTER_MODE    (1)
  685. #define BUFFERED_MODE            (0)
  686.  
  687. STATIC int MaxNonblockingDescriptor = -1;
  688.  
  689. STATIC VOID
  690. UnblockDescriptorCleanup(VOID)
  691. {
  692.     struct UFB * ufb;
  693.     int fd;
  694.  
  695.     /* We look for descriptors we switched into
  696.      * non-blocking mode and reset them back
  697.      * to blocking mode.
  698.      */
  699.     for(fd = 0 ; fd <= MaxNonblockingDescriptor ; fd++)
  700.     {
  701.         ufb = chkufb(fd);
  702.         if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_NON_BLOCKING))
  703.         {
  704.             SetMode((BPTR)ufb->ufbfh,BUFFERED_MODE);
  705.  
  706.             CLEAR_FLAG(ufb->ufbflg,UFB_IS_NON_BLOCKING);
  707.         }
  708.     }
  709. }
  710.  
  711. STATIC BOOL
  712. IsDescriptorNonblocking(int fd)
  713. {
  714.     struct UFB * ufb;
  715.     BOOL result = FALSE;
  716.  
  717.     /* Verify if a descriptor was switched into non-blocking mode. */
  718.     ufb = chkufb(fd);
  719.     if(ufb != NULL)
  720.         result = FLAG_IS_SET(ufb->ufbflg,UFB_IS_NON_BLOCKING);
  721.  
  722.     return(result);
  723. }
  724.  
  725. STATIC VOID
  726. BlockDescriptor(int fd)
  727. {
  728.     struct UFB * ufb;
  729.  
  730.     /* This resets a file descriptor to blocking mode,
  731.      * once it has been set to blocking mode.
  732.      */
  733.     ufb = chkufb(fd);
  734.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_NON_BLOCKING))
  735.     {
  736.         SetMode((BPTR)ufb->ufbfh,BUFFERED_MODE);
  737.  
  738.         CLEAR_FLAG(ufb->ufbflg,UFB_IS_NON_BLOCKING);
  739.     }
  740. }
  741.  
  742. STATIC VOID
  743. UnblockDescriptor(int fd)
  744. {
  745.     struct UFB * ufb;
  746.  
  747.     ufb = chkufb(fd);
  748.     if(ufb != NULL)
  749.     {
  750.         /* Make sure we got a file and it's not already
  751.          * in non-blocking mode.
  752.          */
  753.         if(FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET) && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_NON_BLOCKING))
  754.         {
  755.             /* Try to flip it into single character mode,
  756.              * which we treat as "non-blocking" mode.
  757.              */
  758.             if(SetMode((BPTR)ufb->ufbfh,SINGLE_CHARACTER_MODE))
  759.             {
  760.                 SET_FLAG(ufb->ufbflg,UFB_IS_NON_BLOCKING);
  761.  
  762.                 /* Remember which one we switched. */
  763.                 if(MaxNonblockingDescriptor < fd)
  764.                     MaxNonblockingDescriptor = fd;
  765.             }
  766.         }
  767.     }
  768. }
  769.  
  770. /******************************************************************************/
  771.  
  772. struct SavedDescriptorNode
  773. {
  774.     struct MinNode    sdn_MinNode;
  775.     struct UFB *    sdn_UFB;
  776.     BPTR            sdn_FileHandle;
  777. };
  778.  
  779. STATIC BOOL DescriptorListInitialized = FALSE;
  780. STATIC struct List DescriptorList;
  781.  
  782. STATIC VOID
  783. SaveDescriptorCleanup(VOID)
  784. {
  785.     /* This routine restores all file descriptors
  786.      * we used to map to sockets to use proper file
  787.      * handles.
  788.      */
  789.     if(DescriptorListInitialized)
  790.     {
  791.         struct SavedDescriptorNode * sdn;
  792.  
  793.         for(sdn = (struct SavedDescriptorNode *)DescriptorList.lh_Head ;
  794.             sdn->sdn_MinNode.mln_Succ != NULL ;
  795.             sdn = (struct SavedDescriptorNode *)sdn->sdn_MinNode.mln_Succ)
  796.         {
  797.             /* Make sure that if this file is bound to
  798.              * a socket, the socket is closed.
  799.              */
  800.             if(FLAG_IS_SET(sdn->sdn_UFB->ufbflg,UFB_IS_SOCKET))
  801.             {
  802.                 CloseSocket(sdn->sdn_UFB->ufbfh);
  803.  
  804.                 CLEAR_FLAG(sdn->sdn_UFB->ufbflg,UFB_IS_SOCKET);
  805.             }
  806.  
  807.             sdn->sdn_UFB->ufbfh = sdn->sdn_FileHandle;
  808.         }
  809.     }
  810. }
  811.  
  812. STATIC VOID
  813. RestoreDescriptor(struct UFB * ufb)
  814. {
  815.     ASSERT(ufb != NULL);
  816.  
  817.     /* This routine restores one particular file descriptor
  818.      * which was used as a socket to refer to a proper
  819.      * file handle.
  820.      */
  821.     if(DescriptorListInitialized)
  822.     {
  823.         struct SavedDescriptorNode * sdn;
  824.  
  825.         for(sdn = (struct SavedDescriptorNode *)DescriptorList.lh_Head ;
  826.             sdn->sdn_MinNode.mln_Succ != NULL ;
  827.             sdn = (struct SavedDescriptorNode *)sdn->sdn_MinNode.mln_Succ)
  828.         {
  829.             if(sdn->sdn_UFB == ufb)
  830.             {
  831.                 sdn->sdn_UFB->ufbfh = sdn->sdn_FileHandle;
  832.  
  833.                 Remove((struct Node *)sdn);
  834.                 free(sdn);
  835.  
  836.                 break;
  837.             }
  838.         }
  839.     }
  840. }
  841.  
  842. STATIC BOOL
  843. SaveDescriptor(struct UFB * ufb)
  844. {
  845.     struct SavedDescriptorNode * sdn;
  846.     BOOL result = FALSE;
  847.  
  848.     ASSERT(ufb != NULL);
  849.  
  850.     /* Set up the descriptor list, unless it's already
  851.      * initialized.
  852.      */
  853.     if(NOT DescriptorListInitialized)
  854.     {
  855.         NewList(&DescriptorList);
  856.         DescriptorListInitialized = TRUE;
  857.     }
  858.  
  859.     sdn = malloc(sizeof(*sdn));
  860.     if(sdn != NULL)
  861.     {
  862.         memset(sdn,0,sizeof(*sdn));
  863.  
  864.         /* Remember the file buffer and the file
  865.          * handle attached to the descriptor.
  866.          */
  867.         sdn->sdn_UFB        = ufb;
  868.         sdn->sdn_FileHandle    = ufb->ufbfh;
  869.  
  870.         AddHead(&DescriptorList,(struct Node *)sdn);
  871.  
  872.         result = TRUE;
  873.     }
  874.  
  875.     return(result);
  876. }
  877.  
  878. /******************************************************************************/
  879.  
  880. STATIC BOOL InitialCurrentDirInitialized = FALSE;
  881. STATIC BPTR InitialCurrentDir;
  882. STATIC BPTR ChangedCurrentDir;
  883.  
  884. CBMLIB_DESTRUCTOR(CloseLibsAndDevs)
  885. {
  886.     ENTER();
  887.  
  888.     /* Return to the directory we were in
  889.      * when we started.
  890.      */
  891.     if(InitialCurrentDirInitialized)
  892.     {
  893.         CurrentDir(InitialCurrentDir);
  894.         InitialCurrentDirInitialized = FALSE;
  895.     }
  896.  
  897.     /* If the current directory was changed, unlock it. */
  898.     if(ChangedCurrentDir != ZERO)
  899.     {
  900.         UnLock(ChangedCurrentDir);
  901.         ChangedCurrentDir = ZERO;
  902.     }
  903.  
  904.     CleanupSambaSemaphore();
  905.  
  906.     if(TimerRequest != NULL)
  907.     {
  908.         if(TimerRequest->tr_node.io_Device != NULL)
  909.             CloseDevice((struct IORequest *)TimerRequest);
  910.  
  911.         DeleteIORequest((struct IORequest *)TimerRequest);
  912.         TimerRequest = NULL;
  913.     }
  914.  
  915.     if(TimerPort != NULL)
  916.     {
  917.         DeleteMsgPort(TimerPort);
  918.         TimerPort = NULL;
  919.     }
  920.  
  921.     TimerBase = NULL;
  922.  
  923.     if(SocketBase != NULL)
  924.     {
  925.         CloseLibrary(SocketBase);
  926.         SocketBase = NULL;
  927.     }
  928.  
  929.     if(UserGroupBase != NULL)
  930.     {
  931.         CloseLibrary(UserGroupBase);
  932.         UserGroupBase = NULL;
  933.     }
  934.  
  935.     LEAVE();
  936. }
  937.  
  938. CBMLIB_CONSTRUCTOR(OpenLibsAndDevs)
  939. {
  940.     extern STRPTR _ProgramName;
  941.     BOOL sambaSemaphoreCreated;
  942.     struct LocaleBase * LocaleBase;
  943.     char *timerError = "";
  944.     BPTR sambaLock;
  945.     UBYTE env_buffer[256];
  946.     int result = ERROR;
  947.  
  948.     SETPROGRAMNAME(_ProgramName);
  949.     SETDEBUGLEVEL(0);
  950.  
  951.     ENTER();
  952.  
  953.     SocketBase = OpenLibrary("bsdsocket.library",3);
  954.     UserGroupBase = OpenLibrary("usergroup.library",1);
  955.  
  956.     if(SysBase->lib_Version >= 37)
  957.     {
  958.         TimerPort = CreateMsgPort();
  959.         if(TimerPort != NULL)
  960.         {
  961.             TimerRequest = (struct timerequest *)CreateIORequest(TimerPort,sizeof(*TimerRequest));
  962.             if(TimerRequest != NULL)
  963.             {
  964.                 if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimerRequest,NULL) == OK)
  965.                     TimerBase = TimerRequest->tr_node.io_Device;
  966.                 else
  967.                     timerError = "opening \"timer.device\"";
  968.             }
  969.             else
  970.             {
  971.                 timerError = "creating timer I/O request";
  972.             }
  973.         }
  974.         else
  975.         {
  976.             timerError = "creating timer message port";
  977.         }
  978.     }
  979.  
  980.     /* Try to determine this machine's time zone. */
  981.     LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38);
  982.     if(LocaleBase != NULL)
  983.     {
  984.         struct Locale * locale;
  985.  
  986.         locale = OpenLocale(NULL);
  987.         MinutesWest = locale->loc_GMTOffset;
  988.         CloseLocale(locale);
  989.  
  990.         CloseLibrary((struct Library *)LocaleBase);
  991.     }
  992.  
  993.     ForbidDOS();
  994.  
  995.     /* Try to get a lock on the "Samba:" directory,
  996.      * just to make sure the assignment is in place.
  997.      */
  998.     sambaLock = Lock("Samba:",SHARED_LOCK);
  999.     if(sambaLock != ZERO)
  1000.         UnLock(sambaLock);
  1001.  
  1002.     PermitDOS();
  1003.  
  1004.     /* Initialize the global process ID database. */
  1005.     sambaSemaphoreCreated = SetupSambaSemaphore();
  1006.  
  1007.     if(SocketBase != NULL && UserGroupBase != NULL && TimerBase != NULL &&
  1008.        sambaLock != ZERO && sambaSemaphoreCreated)
  1009.     {
  1010.         STATIC long h_errno = 0;
  1011.         struct timeval now;
  1012.         int error;
  1013.  
  1014.         error = SocketBaseTags(
  1015.             SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))),    &errno,
  1016.             SBTM_SETVAL(SBTC_HERRNOLONGPTR),            &h_errno,
  1017.             SBTM_SETVAL(SBTC_LOGTAGPTR),                _ProgramName,
  1018.             SBTM_SETVAL(SBTC_BREAKMASK),                SIGBREAKF_CTRL_C,
  1019.         TAG_END);
  1020.         if(error != OK)
  1021.         {
  1022.             ReportProblem("Error initializing socket data (error=%ld).",error);
  1023.             goto out;
  1024.         }
  1025.  
  1026.         error = ug_SetupContextTags(_ProgramName,
  1027.             UGT_ERRNOPTR(sizeof(errno)),&errno,
  1028.         TAG_END);
  1029.         if(error != OK)
  1030.         {
  1031.             ReportProblem("Error initializing user group data (error=%ld).",error);
  1032.             goto out;
  1033.         }
  1034.  
  1035.         /* Use a new random number seed. */
  1036.         GetSysTime((APTR)&now);
  1037.         srand(now.tv_secs);
  1038.     }
  1039.     else
  1040.     {
  1041.         if(SocketBase == NULL)
  1042.             ReportProblem("Error opening \"bsdsocket.library\" V3.");
  1043.         else if (UserGroupBase == NULL)
  1044.             ReportProblem("Error opening \"usergroup.library\" V1.");
  1045.         else if (TimerBase == NULL)
  1046.             ReportProblem("Error %s.",timerError);
  1047.         else if (sambaLock == ZERO)
  1048.             ReportProblem("Error finding \"Samba:\" assignment.");
  1049.         else if (NOT sambaSemaphoreCreated)
  1050.             ReportProblem("Error creating Samba semaphore.");
  1051.  
  1052.         goto out;
  1053.     }
  1054.  
  1055.     /* Now try to read any global options that may be set. */
  1056.     if(GetVar("Samba",env_buffer,sizeof(env_buffer)-1,GVF_GLOBAL_ONLY) > 0)
  1057.     {
  1058.         struct RDArgs * rda;
  1059.  
  1060.         rda = (struct RDArgs *)AllocDosObjectTagList(DOS_RDARGS,NULL);
  1061.         if(rda != NULL)
  1062.         {
  1063.             struct
  1064.             {
  1065.                 SWITCH RootMode;
  1066.             } cmd_args;
  1067.  
  1068.             STRPTR cmd_template =
  1069.                 "ROOT/S";
  1070.  
  1071.             strcat(env_buffer,"\n");
  1072.  
  1073.             rda->RDA_Source.CS_Buffer = env_buffer;
  1074.             rda->RDA_Source.CS_Length = strlen(env_buffer);
  1075.             rda->RDA_Source.CS_CurChr = 0;
  1076.             rda->RDA_Flags |= RDAF_NOPROMPT;
  1077.  
  1078.             memset(&cmd_args,0,sizeof(cmd_args));
  1079.  
  1080.             if(ReadArgs(cmd_template,(LONG *)&cmd_args,rda))
  1081.             {
  1082.                 if(cmd_args.RootMode)
  1083.                     RootMode = TRUE;
  1084.  
  1085.                 FreeArgs(rda);
  1086.             }
  1087.  
  1088.             FreeDosObject(DOS_RDARGS,rda);
  1089.         }
  1090.     }
  1091.  
  1092.     /* Initialize the current time zone variable. */
  1093.     __tzset();
  1094.  
  1095.     result = OK;
  1096.  
  1097. out:
  1098.  
  1099.     RETURN(result);
  1100.     return(result);
  1101. }
  1102.  
  1103. /******************************************************************************/
  1104.  
  1105. DESTRUCTOR_P(SocketExit,501)
  1106. {
  1107.     ENTER();
  1108.  
  1109.     SaveDescriptorCleanup();
  1110.     UnblockDescriptorCleanup();
  1111.     CloseUnlinkUnlockCleanup();
  1112.     ForbidDOSCleanup();
  1113.  
  1114.     LEAVE();
  1115. }
  1116.  
  1117. /******************************************************************************/
  1118.  
  1119. CONSTRUCTOR_P(DaemonInit,501)
  1120. {
  1121.     ENTER();
  1122.  
  1123.     DaemonInit();
  1124.  
  1125.     RETURN(0);
  1126.     return(0);
  1127. }
  1128.  
  1129. /******************************************************************************/
  1130.  
  1131. struct MangleInfo
  1132. {
  1133.     char    mi_Substitute[MAX_FILENAME_LEN];
  1134.     char *    mi_OldName;
  1135. };
  1136.  
  1137. STATIC VOID
  1138. UnmangleName(char ** namePtr,struct MangleInfo * mi)
  1139. {
  1140.     /* Reset the name pointer to its previous position. */
  1141.     (*namePtr) = mi->mi_OldName;
  1142. }
  1143.  
  1144. STATIC int
  1145. MangleName(char ** namePtr,struct MangleInfo * mi)
  1146. {
  1147.     char * name = (*namePtr);
  1148.     int result = ERROR;
  1149.  
  1150.     ENTER();
  1151.  
  1152.     SHOWSTRING(name);
  1153.  
  1154.     if(TranslateRelativePath(&name,mi->mi_Substitute,sizeof(mi->mi_Substitute)) == OK)
  1155.     {
  1156.         char * replace = mi->mi_Substitute;
  1157.         int len,i;
  1158.  
  1159.         SHOWSTRING(name);
  1160.  
  1161.         len = strlen(name);
  1162.  
  1163.         /* If there is one, strip the trailing slash. */
  1164.         if(len > 1 && name[len-1] == '/')
  1165.         {
  1166.             SHOWMSG("trailing slash");
  1167.  
  1168.             if(name != replace)
  1169.             {
  1170.                 strcpy(replace,name);
  1171.                 name = replace;
  1172.             }
  1173.  
  1174.             name[--len] = '\0';
  1175.         }
  1176.  
  1177.         if(strcmp(name,".") == SAME)
  1178.         {
  1179.             SHOWMSG("dot file");
  1180.  
  1181.             /* Convert to current directory. */
  1182.             name = "";
  1183.         }
  1184.         else if (strcmp(name,"..") == SAME)
  1185.         {
  1186.             SHOWMSG("dot dot file");
  1187.  
  1188.             /* Convert to parent directory. */
  1189.             name = "/";
  1190.         }
  1191.         else if (strncmp(name,"./",2) == SAME)
  1192.         {
  1193.             SHOWMSG("reference to local dir");
  1194.  
  1195.             /* Retain just the name. */
  1196.             name += 2;
  1197.         }
  1198.         else if (strncmp(name,"../",3) == SAME)
  1199.         {
  1200.             SHOWMSG("reference to parent dir");
  1201.  
  1202.             /* Convert to parent directory. */
  1203.             name += 2;
  1204.         }
  1205.         else if (strncmp(name,"/",1) == SAME)
  1206.         {
  1207.             SHOWMSG("root dir");
  1208.  
  1209.             /* Ok, so this is an absolute path. We first
  1210.              * check for a few special cases, the first
  1211.              * being a reference to "/tmp".
  1212.              */
  1213.             if(Strnicmp(name,"/tmp",4) == SAME && (name[4] == '/' || name[4] == '\0'))
  1214.             {
  1215.                 SHOWMSG("tmp");
  1216.  
  1217.                 if(name[4] == '/')
  1218.                 {
  1219.                     /* Convert "/tmp/foo" to "T:foo". */
  1220.                     strcpy(replace,"T:");
  1221.                     memmove(&replace[2],&name[5],strlen(&name[5])+1);
  1222.                 }
  1223.                 else
  1224.                 {
  1225.                     /* Convert "/tmp" to "T:". */
  1226.                     strcpy(replace,"T:");
  1227.                 }
  1228.  
  1229.                 name = replace;
  1230.             }
  1231.             else if(Strnicmp(name,"/dev/",5) == SAME)
  1232.             {
  1233.                 SHOWMSG("dev");
  1234.  
  1235.                 /* Except for "/dev/null" all references to
  1236.                  * files in "/dev" are redirected to nonexistant
  1237.                  * files. Note that this relies upon the fact
  1238.                  * that "NIL:" is not a true device.
  1239.                  */
  1240.                 if(Stricmp(name,"/dev/null") == SAME)
  1241.                     name = "NIL:";
  1242.                 else
  1243.                     name = "NIL:this_file_never_opens";
  1244.             }
  1245.             else
  1246.             {
  1247.                 int i,rest = 0,len = 0;
  1248.  
  1249.                 SHOWMSG("absolute");
  1250.  
  1251.                 /* Find out how long the first component
  1252.                  * of the absolute path is.
  1253.                  */
  1254.                 for(i = 1 ; i <= strlen(name) ; i++)
  1255.                 {
  1256.                     if(name[i] == '/' || name[i] == '\0')
  1257.                     {
  1258.                         len = i-1;
  1259.  
  1260.                         /* Is there anything following
  1261.                          * the path name?
  1262.                          */
  1263.                         if(name[i] == '/')
  1264.                             rest = i+1;
  1265.  
  1266.                         break;
  1267.                     }
  1268.                 }
  1269.  
  1270.                 /* Copy the first component and
  1271.                  * attach a colon. "/foo" becomes
  1272.                  * "foo:" (without the trailing NUL
  1273.                  * byte, this will get attached
  1274.                  * later).
  1275.                  */
  1276.                 memmove(replace,&name[1],len);
  1277.                 replace[len++] = ':';
  1278.  
  1279.                 /* Now add the finishing touches. "/foo/bar" finally
  1280.                  * becomes "foo:bar" and "/foo" becomes "foo:" with the
  1281.                  * trailing NUL byte attached.
  1282.                  */
  1283.                 if(rest > 0)
  1284.                     memmove(&replace[len],&name[rest],strlen(&name[rest])+1);
  1285.                 else
  1286.                     replace[len] = '\0';
  1287.  
  1288.                 name = replace;
  1289.             }
  1290.         }
  1291.  
  1292.         SHOWSTRING(name);
  1293.  
  1294.         /* Convert any "./" or "../" embedded in the name
  1295.          * if necessary.
  1296.          */
  1297.         SHOWMSG("stripping embedded slashes");
  1298.         for(i = 0 ; i < strlen(name) ; i++)
  1299.         {
  1300.             if(strncmp(&name[i],"./",2) == SAME ||
  1301.                strncmp(&name[i],"../",3) == SAME)
  1302.             {
  1303.                 char * from    = name;
  1304.                 char * to    = replace;
  1305.  
  1306.                 name = replace;
  1307.  
  1308.                 while((*from) != '\0')
  1309.                 {
  1310.                     if((*from) == '.')
  1311.                     {
  1312.                         if(from[1] == '/' || from[1] == '\0')
  1313.                         {
  1314.                             /* "."  -> "" (done)
  1315.                              * "./" -> "" (continue)
  1316.                              */
  1317.                             if(from[1] == '\0')
  1318.                                 break;
  1319.                             else
  1320.                                 from += 2;
  1321.                         }
  1322.                         else if (from[1] == '.' && (from[2] == '/' || from[2] == '\0'))
  1323.                         {
  1324.                             /* ".."  -> "/" (done)
  1325.                              * "../" -> "/" (continue)
  1326.                              */
  1327.                             (*to++) = '/';
  1328.  
  1329.                             if(from[2] == '\0')
  1330.                                 break;
  1331.                             else
  1332.                                 from += 3;
  1333.                         }
  1334.                         else
  1335.                         {
  1336.                             (*to++) = (*from++);
  1337.                         }
  1338.                     }
  1339.                     else
  1340.                     {
  1341.                         (*to++) = (*from++);
  1342.                     }
  1343.                 }
  1344.  
  1345.                 (*to) = '\0';
  1346.  
  1347.                 break;
  1348.             }
  1349.         }
  1350.  
  1351.         /* Reduce any "//" embedded in the name if
  1352.          * necessary.
  1353.          */
  1354.         SHOWMSG("stripping more embedded slashes");
  1355.         for(i = 0 ; i < ((int)strlen(name))-1 ; i++)
  1356.         {
  1357.             if(name[i] == '/' && name[i+1] == '/')
  1358.             {
  1359.                 int position,len;
  1360.  
  1361.                 if(name != replace)
  1362.                 {
  1363.                     strcpy(replace,name);
  1364.                     name = replace;
  1365.                 }
  1366.  
  1367.                 len = strlen(name);
  1368.  
  1369.                 position = len - 1;
  1370.                 while(position > 1 && name[position] != ':')
  1371.                 {
  1372.                     /* "foo/bar//baz" -> "foo/baz" */
  1373.                     if(name[position] == '/' && name[position-1] == '/')
  1374.                     {
  1375.                         int componentLen;
  1376.  
  1377.                         /* Move in front of the name component preceding the "//". */
  1378.                         componentLen = 0;
  1379.                         for(i = position - 2 ; i > 0 && name[i] != ':' && name[i] != '/' ; i--)
  1380.                             componentLen++;
  1381.  
  1382.                         if(componentLen > 0)
  1383.                         {
  1384.                             memmove(&name[position - (componentLen + 1)],&name[position + 1],len - (position + 1));
  1385.  
  1386.                             len -= componentLen + 2;
  1387.                             name[len] = '\0';
  1388.  
  1389.                             position -= componentLen + 1;
  1390.                         }
  1391.                     }
  1392.  
  1393.                     position--;
  1394.                 }
  1395.  
  1396.                 break;
  1397.             }
  1398.         }
  1399.  
  1400.         D(("original name |%s|",(*namePtr)));
  1401.         D((" mangled name |%s|",name));
  1402.  
  1403.         /* Look for extra colon characters
  1404.          * embedded in the name (as in "foo:bar:baz"
  1405.          * or "foo/bar:baz") which really don't
  1406.          * belong here.
  1407.          */
  1408.         SHOWMSG("stripping colons");
  1409.         len = strlen(name);
  1410.         for(i = 0 ; i < len ; i++)
  1411.         {
  1412.             if(name[i] == ':' || name[i] == '/')
  1413.             {
  1414.                 int j;
  1415.  
  1416.                 for(j = i+1 ; j < len ; j++)
  1417.                 {
  1418.                     if(name[j] == ':')
  1419.                     {
  1420.                         errno = EINVAL; /* invalid name */
  1421.                         goto out;
  1422.                     }
  1423.                 }
  1424.  
  1425.                 break;
  1426.             }
  1427.         }
  1428.  
  1429.         /* Now check if the file name is longer than the
  1430.          * maximum supported by the ROM file system. This
  1431.          * is to avoid name space clashes.
  1432.          */
  1433.         SHOWMSG("checking file name length");
  1434.         if(strlen(FilePart((STRPTR)name)) > MAX_FFS_NAME_LEN)
  1435.         {
  1436.             LONG error = OK;
  1437.             BPTR fileLock;
  1438.  
  1439.             D(("name is probably too long (%ld > %ld)",strlen(FilePart((STRPTR)name)) > MAX_FFS_NAME_LEN));
  1440.  
  1441.             /* This is a tricky issue: the filing system we are talking
  1442.              * to may be able to handle more than 30 characters, but then
  1443.              * it may be not, it's impossible to tell. We adopt the following
  1444.              * strategy: we try to access the named file and compare its
  1445.              * name against the one reported by the file system. If the name
  1446.              * reported by the file system is shorter than the one provided,
  1447.              * but matches it otherwise, we will assume that trouble is underway
  1448.              * and back out backwards.
  1449.              */
  1450.  
  1451.             ForbidDOS();
  1452.  
  1453.             fileLock = Lock((STRPTR)name,SHARED_LOCK);
  1454.             if(fileLock != ZERO)
  1455.             {
  1456.                 D_S(struct FileInfoBlock,fib);
  1457.  
  1458.                 if(Examine(fileLock,fib))
  1459.                 {
  1460.                     STRPTR file_name = FilePart((STRPTR)name);
  1461.                     int len;
  1462.  
  1463.                     /* Now check if the name reported by the
  1464.                      * filing system is shorter than the
  1465.                      * one we asked for, but matches otherwise.
  1466.                      */
  1467.                     len = strlen(fib->fib_FileName);
  1468.                     if(strlen(file_name) > len && Strnicmp(file_name,fib->fib_FileName,len) == SAME)
  1469.                     {
  1470.                         /* The name is too long to handle. */
  1471.                         error = ERROR_LINE_TOO_LONG;
  1472.                     }
  1473.                 }
  1474.                 else
  1475.                 {
  1476.                     error = IoErr();
  1477.                 }
  1478.  
  1479.                 UnLock(fileLock);
  1480.             }
  1481.             else
  1482.             {
  1483.                 error = IoErr();
  1484.             }
  1485.  
  1486.             PermitDOS();
  1487.  
  1488.             /* We don't complain if the file does
  1489.              * not exist, but if it is currently in
  1490.              * use, on a volume that's not currently
  1491.              * mounted, etc. we will complain.
  1492.              */
  1493.             if(error != OK && error != ERROR_OBJECT_NOT_FOUND)
  1494.             {
  1495.                 SetIoErr(error);
  1496.                 MapIoErrToErrno();
  1497.  
  1498.                 goto out;
  1499.             }
  1500.         }
  1501.  
  1502.         mi->mi_OldName = (*namePtr);
  1503.         (*namePtr) = name;
  1504.  
  1505.         result = OK;
  1506.     }
  1507.  
  1508. out:
  1509.  
  1510.     RETURN(result);
  1511.     return(result);
  1512. }
  1513.  
  1514. /******************************************************************************/
  1515.  
  1516. STATIC int MaxOpenDescriptor = -1;
  1517.  
  1518. STATIC VOID
  1519. CloseUnlinkUnlockCleanup(VOID)
  1520. {
  1521.     struct UFB * ufb;
  1522.     int fd;
  1523.  
  1524.     ForbidDOS();
  1525.  
  1526.     /* Don't let anybody stop us. */
  1527.     signal(SIGINT,SIG_IGN);
  1528.     signal(SIGTERM,SIG_IGN);
  1529.  
  1530.     /* We look for descriptors we marked for
  1531.      * deletion.
  1532.      */
  1533.     for(fd = 0 ; fd <= MaxOpenDescriptor ; fd++)
  1534.     {
  1535.         CleanupFileLocks(fd);
  1536.  
  1537.         ufb = chkufb(fd);
  1538.         if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_UNLINK))
  1539.         {
  1540.             char fileName[MAX_FILENAME_LEN];
  1541.             BOOL removeIt;
  1542.  
  1543.             removeIt = NameFromFH((BPTR)ufb->ufbfh,fileName,sizeof(fileName));
  1544.  
  1545.             CLEAR_FLAG(ufb->ufbflg,UFB_UNLINK);
  1546.  
  1547.             close(fd);
  1548.  
  1549.             if(removeIt)
  1550.                 DeleteFile(fileName);
  1551.         }
  1552.     }
  1553.  
  1554.     PermitDOS();
  1555. }
  1556.  
  1557. int
  1558. amiga_unlink(char *name)
  1559. {
  1560.     struct MangleInfo mi;
  1561.     BPTR fileLock;
  1562.     int result = ERROR;
  1563.  
  1564.     chkabort();
  1565.  
  1566.     ASSERT(name != NULL);
  1567.  
  1568.     ENTER();
  1569.     SHOWSTRING(name);
  1570.  
  1571.     if(MangleName(&name,&mi) == OK)
  1572.     {
  1573.         LONG error = OK;
  1574.  
  1575.         ForbidDOS();
  1576.  
  1577.         fileLock = Lock(name,SHARED_LOCK);
  1578.         if(fileLock != ZERO)
  1579.         {
  1580.             D_S(struct FileInfoBlock,fib);
  1581.  
  1582.             if(Examine(fileLock,fib))
  1583.             {
  1584.                 UnLock(fileLock);
  1585.                 fileLock = ZERO;
  1586.  
  1587.                 /* Make sure that we get to remove
  1588.                  * a file, as the name implies.
  1589.                  */
  1590.                 if(FIB_IS_FILE(fib))
  1591.                 {
  1592.                     if(DeleteFile(name))
  1593.                         result = OK;
  1594.                     else
  1595.                         error = IoErr();
  1596.                 }
  1597.                 else
  1598.                 {
  1599.                     errno = EISDIR;
  1600.                 }
  1601.             }
  1602.             else
  1603.             {
  1604.                 error = IoErr();
  1605.             }
  1606.  
  1607.             UnLock(fileLock);
  1608.         }
  1609.         else
  1610.         {
  1611.             error = IoErr();
  1612.         }
  1613.  
  1614.         PermitDOS();
  1615.  
  1616.         /* Check if we couldn't delete the file in
  1617.          * question because there still is a file
  1618.          * handle attached to it. If we can find that
  1619.          * file, we will mark it for deletion lateron
  1620.          * when the file is closed.
  1621.          */
  1622.         if(result != OK && error == ERROR_OBJECT_IN_USE)
  1623.         {
  1624.             char parentDirName[MAX_FILENAME_LEN];
  1625.             BOOL foundParentDirName;
  1626.             BPTR fileParentDir;
  1627.             int i;
  1628.  
  1629.             ASSERT(strlen(name) < sizeof(parentDirName));
  1630.  
  1631.             strcpy(parentDirName,name);
  1632.             foundParentDirName = FALSE;
  1633.  
  1634.             for(i = ((int)strlen(parentDirName))-1 ; i >= 0 ; i--)
  1635.             {
  1636.                 if(parentDirName[i] == ':')
  1637.                 {
  1638.                     if(parentDirName[i+1] != '\0')
  1639.                     {
  1640.                         parentDirName[i+1] = '\0';
  1641.                         foundParentDirName = TRUE;
  1642.                     }
  1643.  
  1644.                     break;
  1645.                 }
  1646.                 else if (parentDirName[i] == '/')
  1647.                 {
  1648.                     parentDirName[i] = '\0';
  1649.                     foundParentDirName = TRUE;
  1650.                     break;
  1651.                 }
  1652.             }
  1653.  
  1654.             /* Did we find this file's parent directory name? */
  1655.             if(foundParentDirName)
  1656.             {
  1657.                 D(("locking |%s|",parentDirName));
  1658.  
  1659.                 /* Get a lock on the file's parent directory. */
  1660.                 fileParentDir = Lock(parentDirName,SHARED_LOCK);
  1661.                 if(fileParentDir != ZERO)
  1662.                 {
  1663.                     BPTR descriptorParentDir;
  1664.                     BOOL gotIt = FALSE;
  1665.                     struct UFB * ufb;
  1666.                     int fd;
  1667.  
  1668.                     for(fd = 0 ; fd <= MaxOpenDescriptor ; fd++)
  1669.                     {
  1670.                         ufb = chkufb(fd);
  1671.                         if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  1672.                         {
  1673.                             /* And also get a lock on the file
  1674.                              * descriptor's parent directory.
  1675.                              */
  1676.                             descriptorParentDir = ParentOfFH((BPTR)ufb->ufbfh);
  1677.                             if(descriptorParentDir != ZERO)
  1678.                             {
  1679.                                 /* Are the two pointing to the same drawer? */
  1680.                                 if(SameLock(fileParentDir,descriptorParentDir) == LOCK_SAME)
  1681.                                 {
  1682.                                     D_S(struct FileInfoBlock,fib);
  1683.  
  1684.                                     if(ExamineFH((BPTR)ufb->ufbfh,fib))
  1685.                                     {
  1686.                                         /* Check if the two share the same name. */
  1687.                                         if(Stricmp(fib->fib_FileName,FilePart(name)) == SAME)
  1688.                                         {
  1689.                                             /* Mark this file for deletion. */
  1690.                                             SET_FLAG(ufb->ufbflg,UFB_UNLINK);
  1691.  
  1692.                                             gotIt = TRUE;
  1693.                                             error = OK;
  1694.                                             result = OK;
  1695.                                         }
  1696.                                     }
  1697.                                     else
  1698.                                     {
  1699.                                         SHOWMSG("couldn't examine the descriptor");
  1700.                                     }
  1701.                                 }
  1702.                                 else
  1703.                                 {
  1704.                                     SHOWMSG("file and descriptor don't live in the same drawer");
  1705.                                 }
  1706.  
  1707.                                 UnLock(descriptorParentDir);
  1708.                             }
  1709.                             else
  1710.                             {
  1711.                                 SHOWMSG("the descriptor doesn't have a parent directory (huh?!?)");
  1712.                             }
  1713.                         }
  1714.  
  1715.                         if(gotIt)
  1716.                             break;
  1717.                     }
  1718.  
  1719.                     UnLock(fileParentDir);
  1720.                 }
  1721.                 else
  1722.                 {
  1723.                     D(("couldn't get a lock on |%s|",parentDirName));
  1724.                 }
  1725.             }
  1726.             else
  1727.             {
  1728.                 D(("didn't find parent dir name of |%s|",name));
  1729.             }
  1730.         }
  1731.  
  1732.         /* Take care of the AmigaDOS error
  1733.          * code, if there is any.
  1734.          */
  1735.         if(result != OK && error != OK)
  1736.         {
  1737.             SetIoErr(error);
  1738.             MapIoErrToErrno();
  1739.         }
  1740.  
  1741.         UnmangleName(&name,&mi);
  1742.     }
  1743.  
  1744.     RETURN(result);
  1745.     return(result);
  1746. }
  1747.  
  1748. int
  1749. amiga_open(char *name,int mode,int prot)
  1750. {
  1751.     struct MangleInfo mi;
  1752.     int result = ERROR;
  1753.  
  1754.     chkabort();
  1755.  
  1756.     ASSERT(name != NULL);
  1757.  
  1758.     ENTER();
  1759.     SHOWSTRING(name);
  1760.     SHOWVALUE(mode);
  1761.     SHOWVALUE(prot);
  1762.  
  1763.     if(MangleName(&name,&mi) == OK)
  1764.     {
  1765.         /* Clear the "no delay" flag since the SAS/C
  1766.          * runtime library does not support it.
  1767.          */
  1768.         CLEAR_FLAG(mode,O_NONBLOCK);
  1769.  
  1770.         ForbidDOS();
  1771.  
  1772.         result = open(name,mode,prot);
  1773.         if(result != ERROR && MaxOpenDescriptor < result)
  1774.             MaxOpenDescriptor = result;
  1775.  
  1776.         PermitDOS();
  1777.  
  1778.         UnmangleName(&name,&mi);
  1779.     }
  1780.  
  1781.     RETURN(result);
  1782.     return(result);
  1783. }
  1784.  
  1785. /******************************************************************************/
  1786.  
  1787. STATIC char CurrentDirName[MAX_FILENAME_LEN] = "";
  1788.  
  1789. int
  1790. amiga_chdir(char *path)
  1791. {
  1792.     BOOL isAbsolutePath;
  1793.     struct MangleInfo mi;
  1794.     int result = ERROR;
  1795.  
  1796.     chkabort();
  1797.  
  1798.     ASSERT(path != NULL);
  1799.  
  1800.     ENTER();
  1801.     SHOWSTRING(path);
  1802.  
  1803.     /* Is this an absolute path? */
  1804.     isAbsolutePath = (BOOL)(path[0] == '/');
  1805.  
  1806.     if(MangleName(&path,&mi) == OK)
  1807.     {
  1808.         BPTR drawerLock;
  1809.  
  1810.         D(("chdir(\"%s\")",path));
  1811.  
  1812.         ForbidDOS();
  1813.  
  1814.         drawerLock = Lock(path,SHARED_LOCK);
  1815.         if(drawerLock != ZERO)
  1816.         {
  1817.             D_S(struct FileInfoBlock,fib);
  1818.  
  1819.             if(Examine(drawerLock,fib))
  1820.             {
  1821.                 /* We can only move into drawers. */
  1822.                 if(FIB_IS_DRAWER(fib))
  1823.                 {
  1824.                     /* If necessary, get the name of
  1825.                      * the drawer to move into.
  1826.                      */
  1827.                     if(NOT isAbsolutePath)
  1828.                     {
  1829.                         UBYTE localName[MAX_FILENAME_LEN];
  1830.  
  1831.                         if(NameFromLock(drawerLock,localName,sizeof(localName)))
  1832.                             result = MapFileNameAmigaToUnix(localName,CurrentDirName,sizeof(CurrentDirName));
  1833.                         else
  1834.                             MapIoErrToErrno();
  1835.                     }
  1836.                     else
  1837.                     {
  1838.                         result = OK;
  1839.                     }
  1840.  
  1841.                     /* If everything went well,
  1842.                      * move into the drawer.
  1843.                      */
  1844.                     if(result == OK)
  1845.                     {
  1846.                         BPTR oldDrawer;
  1847.  
  1848.                         oldDrawer = CurrentDir(drawerLock);
  1849.  
  1850.                         /* Unlock the old drawer we came from
  1851.                          * unless we want to return to it
  1852.                          * when the program exits.
  1853.                          */
  1854.                         if(InitialCurrentDirInitialized)
  1855.                         {
  1856.                             UnLock(oldDrawer);
  1857.                         }
  1858.                         else
  1859.                         {
  1860.                             InitialCurrentDir = oldDrawer;
  1861.                             InitialCurrentDirInitialized = TRUE;
  1862.                         }
  1863.  
  1864.                         /* Make sure that this drawer is going
  1865.                          * to be unlocked when the program exits.
  1866.                          */
  1867.                         ChangedCurrentDir = drawerLock;
  1868.                     }
  1869.                 }
  1870.                 else
  1871.                 {
  1872.                     errno = ENOTDIR;
  1873.                 }
  1874.             }
  1875.             else
  1876.             {
  1877.                 MapIoErrToErrno();
  1878.             }
  1879.  
  1880.             if(result != OK)
  1881.                 UnLock(drawerLock);
  1882.         }
  1883.         else
  1884.         {
  1885.             MapIoErrToErrno();
  1886.         }
  1887.  
  1888.         PermitDOS();
  1889.  
  1890.         UnmangleName(&path,&mi);
  1891.  
  1892.         if(result == OK && isAbsolutePath)
  1893.             strcpy(CurrentDirName,path);
  1894.     }
  1895.  
  1896.     RETURN(result);
  1897.     return(result);
  1898. }
  1899.  
  1900. /******************************************************************************/
  1901.  
  1902. struct OpenDirNode
  1903. {
  1904.     struct MinNode            odn_MinNode;
  1905.     BPTR                    odn_FileLock;
  1906.     struct FileInfoBlock    odn_FIB;
  1907.     struct List                odn_VolumeList;
  1908.     DIR                        odn_DIR;
  1909.     BOOL                    odn_ReadingVolumes;
  1910.     struct dirent            odn_DirectoryEntry;
  1911.     struct Node *            odn_NextNode;
  1912.     ULONG                    odn_NextDirEntryIndex;
  1913.     LONG                    odn_ParentDirKey;
  1914. };
  1915.  
  1916. STATIC struct List OpenDirList;
  1917. STATIC BOOL OpenDirListInitialized = FALSE;
  1918.  
  1919. STATIC ULONG RootBlocks = 0;
  1920. STATIC ULONG RootBlocksUsed = 0;
  1921.  
  1922. STATIC VOID
  1923. OpenDirCleanup(VOID)
  1924. {
  1925.     struct OpenDirNode * odn;
  1926.  
  1927.     /* Unlock all directories still being scanned
  1928.      * when exit() was called.
  1929.      */
  1930.     for(odn = (struct OpenDirNode *)OpenDirList.lh_Head ;
  1931.         odn->odn_MinNode.mln_Succ != NULL ;
  1932.         odn = (struct OpenDirNode *)odn->odn_MinNode.mln_Succ)
  1933.     {
  1934.         UnLock(odn->odn_FileLock);
  1935.     }
  1936. }
  1937.  
  1938. DIR *
  1939. amiga_opendir(char *dirName)
  1940. {
  1941.     char localDirName[MAX_FILENAME_LEN];
  1942.     struct List volumeList;
  1943.     struct Node * node;
  1944.     DIR *result = NULL;
  1945.  
  1946.     chkabort();
  1947.  
  1948.     ASSERT(dirName != NULL);
  1949.  
  1950.     ENTER();
  1951.  
  1952.     SHOWSTRING(dirName);
  1953.  
  1954.     /* This is for buffering the list of available volumes. */
  1955.     NewList(&volumeList);
  1956.  
  1957.     /* Make sure that the directory list is
  1958.      * set up properly.
  1959.      */
  1960.     if(NOT OpenDirListInitialized)
  1961.     {
  1962.         NewList(&OpenDirList);
  1963.         OpenDirListInitialized = TRUE;
  1964.         atexit(OpenDirCleanup);
  1965.     }
  1966.  
  1967.     if(TranslateRelativePath(&dirName,localDirName,sizeof(localDirName)) == OK)
  1968.     {
  1969.         /* Check if we are to scan the virtual root directory. */
  1970.         if(strcmp(dirName,"/") == SAME)
  1971.         {
  1972.             struct OpenDirNode * odn;
  1973.  
  1974.             odn = malloc(sizeof(*odn));
  1975.             if(odn != NULL)
  1976.             {
  1977.                 struct DosList * dol;
  1978.  
  1979.                 RootBlocks = RootBlocksUsed = 0;
  1980.  
  1981.                 memset(odn,0,sizeof(*odn));
  1982.                 odn->odn_ReadingVolumes = TRUE;
  1983.                 odn->odn_DIR.dd_buf = (char *)odn;
  1984.                 NewList(&odn->odn_VolumeList);
  1985.  
  1986.                 AddHead(&OpenDirList,(struct Node *)odn);
  1987.  
  1988.                 errno = OK;
  1989.  
  1990.                 /* Now collect all volumes in the system. */
  1991.                 dol = NextDosEntry(LockDosList(LDF_VOLUMES|LDF_READ),
  1992.                                                LDF_VOLUMES|LDF_READ);
  1993.                 while(dol != NULL)
  1994.                 {
  1995.                     /* Does the volume refer to a medium that is right
  1996.                      * now present in the drive?
  1997.                      */
  1998.                     if(dol->dol_Task != NULL)
  1999.                     {
  2000.                         STRPTR name;
  2001.  
  2002.                         name = BADDR(dol->dol_Name);
  2003.                         if(name != NULL && name[0] > 0)
  2004.                         {
  2005.                             LONG len;
  2006.  
  2007.                             len = name[0];
  2008.  
  2009.                             node = malloc(sizeof(*node) + len + 2);
  2010.                             if(node != NULL)
  2011.                             {
  2012.                                 node->ln_Name = (char *)(node + 1);
  2013.                                 memcpy(node->ln_Name,name+1,len);
  2014.                                 node->ln_Name[len++] = ':';
  2015.                                 node->ln_Name[len] = '\0';
  2016.  
  2017.                                 AddTail(&volumeList,node);
  2018.                             }
  2019.                             else
  2020.                             {
  2021.                                 errno = ENOMEM;
  2022.                                 break;
  2023.                             }
  2024.                         }
  2025.                     }
  2026.  
  2027.                     dol = NextDosEntry(dol,LDF_VOLUMES|LDF_READ);
  2028.                 }
  2029.  
  2030.                 UnLockDosList(LDF_VOLUMES|LDF_READ);
  2031.  
  2032.                 /* If everything went well, proceed to examine every
  2033.                  * volume previously added to the local volume list.
  2034.                  * This procedure is necessary to avoid sending
  2035.                  * packets to file systems while the DosList is
  2036.                  * locked, which is a big NO-NO.
  2037.                  */
  2038.                 if(errno == OK)
  2039.                 {
  2040.                     D_S(struct InfoData,id);
  2041.                     struct MsgPort * task;
  2042.  
  2043.                     result = &odn->odn_DIR;
  2044.  
  2045.                     while((node = RemHead(&volumeList)) != NULL)
  2046.                     {
  2047.                         task = DeviceProc(node->ln_Name);
  2048.                         if(task != NULL)
  2049.                         {
  2050.                             /* Is there a disk present? */
  2051.                             if(DoPkt(task,ACTION_DISK_INFO,MKBADDR(id),    0,0,0,0))
  2052.                             {
  2053.                                 /* Collect the number of blocks used and
  2054.                                  * available in our fake root directory.
  2055.                                  * Not that it matters much...
  2056.                                  */
  2057.                                 if(id->id_BytesPerBlock == 512)
  2058.                                 {
  2059.                                     RootBlocks        += id->id_NumBlocks;
  2060.                                     RootBlocksUsed    += id->id_NumBlocksUsed;
  2061.                                 }
  2062.                                 else
  2063.                                 {
  2064.                                     RootBlocks        += (id->id_NumBlocks * id->id_BytesPerBlock) / 512;
  2065.                                     RootBlocksUsed    += (id->id_NumBlocksUsed * id->id_BytesPerBlock) / 512;
  2066.                                 }
  2067.  
  2068.                                 /* Remove the trailing colon character. */
  2069.                                 node->ln_Name[strlen(node->ln_Name)-1] = '\0';
  2070.  
  2071.                                 AddTail(&odn->odn_VolumeList,node);
  2072.  
  2073.                                 if(odn->odn_NextNode == NULL)
  2074.                                     odn->odn_NextNode = node;
  2075.  
  2076.                                 node = NULL;
  2077.                             }
  2078.                         }
  2079.  
  2080.                         if(node != NULL)
  2081.                             free(node);
  2082.                     }
  2083.                 }
  2084.             }
  2085.             else
  2086.             {
  2087.                 errno = ENOMEM;
  2088.             }
  2089.         }
  2090.         else
  2091.         {
  2092.             struct MangleInfo mi;
  2093.  
  2094.             if(MangleName(&dirName,&mi) == OK)
  2095.             {
  2096.                 BPTR fileLock;
  2097.  
  2098.                 ForbidDOS();
  2099.  
  2100.                 fileLock = Lock(dirName,SHARED_LOCK);
  2101.                 if(fileLock != ZERO)
  2102.                 {
  2103.                     struct OpenDirNode * odn;
  2104.  
  2105.                     odn = malloc(sizeof(*odn));
  2106.                     if(odn != NULL)
  2107.                     {
  2108.                         BPTR parentDir;
  2109.  
  2110.                         memset(odn,0,sizeof(*odn));
  2111.  
  2112.                         parentDir = ParentDir(fileLock);
  2113.                         if(parentDir != ZERO)
  2114.                         {
  2115.                             if(Examine(parentDir,&odn->odn_FIB))
  2116.                                 odn->odn_ParentDirKey = odn->odn_FIB.fib_DiskKey;
  2117.  
  2118.                             UnLock(parentDir);
  2119.                         }
  2120.  
  2121.                         if(Examine(fileLock,&odn->odn_FIB))
  2122.                         {
  2123.                             /* Make sure that we are
  2124.                              * trying to read a drawer
  2125.                              * and not a file.
  2126.                              */
  2127.                             if(FIB_IS_DRAWER(&odn->odn_FIB))
  2128.                             {
  2129.                                 odn->odn_DIR.dd_buf = (char *)odn;
  2130.                                 odn->odn_FileLock = fileLock;
  2131.                                 NewList(&odn->odn_VolumeList);
  2132.  
  2133.                                 /* The lock has been "swallowed"
  2134.                                  * by the dir node; make sure that
  2135.                                  * we don't unlock it.
  2136.                                  */
  2137.                                 fileLock = ZERO;
  2138.  
  2139.                                 AddHead(&OpenDirList,(struct Node *)odn);
  2140.                                 result = &odn->odn_DIR;
  2141.                             }
  2142.                             else
  2143.                             {
  2144.                                 errno = ENOTDIR;
  2145.                             }
  2146.                         }
  2147.                         else
  2148.                         {
  2149.                             MapIoErrToErrno();
  2150.                         }
  2151.  
  2152.                         if(result == NULL)
  2153.                             free(odn);
  2154.                     }
  2155.                     else
  2156.                     {
  2157.                         errno = ENOMEM;
  2158.                     }
  2159.  
  2160.                     UnLock(fileLock);
  2161.                 }
  2162.                 else
  2163.                 {
  2164.                     MapIoErrToErrno();
  2165.                 }
  2166.  
  2167.                 PermitDOS();
  2168.  
  2169.                 UnmangleName(&dirName,&mi);
  2170.             }
  2171.         }
  2172.     }
  2173.  
  2174.     /* Get rid of any leftovers. */
  2175.     while((node = RemHead(&volumeList)) != NULL)
  2176.         free(node);
  2177.  
  2178.     RETURN(result);
  2179.     return(result);
  2180. }
  2181.  
  2182. VOID
  2183. amiga_closedir(DIR *dir)
  2184. {
  2185.     ENTER();
  2186.  
  2187.     if(dir != NULL)
  2188.     {
  2189.         struct OpenDirNode * odn;
  2190.  
  2191.         odn = (struct OpenDirNode *)dir->dd_buf;
  2192.         if(odn != NULL)
  2193.         {
  2194.             struct Node * node;
  2195.  
  2196.             Remove((struct Node *)odn);
  2197.  
  2198.             while((node = RemHead(&odn->odn_VolumeList)) != NULL)
  2199.                 free(node);
  2200.  
  2201.             UnLock(odn->odn_FileLock);
  2202.             free(odn);
  2203.         }
  2204.     }
  2205.  
  2206.     chkabort();
  2207.  
  2208.     LEAVE();
  2209. }
  2210.  
  2211. struct dirent *
  2212. amiga_readdir(DIR *dir)
  2213. {
  2214.     struct dirent * result = NULL;
  2215.  
  2216.     ENTER();
  2217.  
  2218.     chkabort();
  2219.  
  2220.     if(dir != NULL)
  2221.     {
  2222.         struct OpenDirNode * odn;
  2223.  
  2224.         odn = (struct OpenDirNode *)dir->dd_buf;
  2225.         if(odn != NULL)
  2226.         {
  2227.             struct dirent * d = &odn->odn_DirectoryEntry;
  2228.  
  2229.             if(odn->odn_ReadingVolumes)
  2230.             {
  2231.                 SHOWMSG("we are reading the virtual root directory");
  2232.  
  2233.                 /* The first directory entry points
  2234.                  * back to the directory itself.
  2235.                  */
  2236.                 if(odn->odn_NextDirEntryIndex == 0)
  2237.                 {
  2238.                     SHOWMSG("this is the first read attempt; returning the dot.");
  2239.  
  2240.                     strcpy(d->d_name,".");
  2241.  
  2242.                     d->d_ino    = ++odn->odn_NextDirEntryIndex;
  2243.                     d->d_namlen    = strlen(d->d_name);
  2244.  
  2245.                     result = d;
  2246.                 }
  2247.                 else
  2248.                 {
  2249.                     /* Return the next volume in the list. */
  2250.                     if(odn->odn_NextNode != NULL && odn->odn_NextNode->ln_Succ != NULL)
  2251.                     {
  2252.                         ASSERT(sizeof(d->d_name) >= strlen(odn->odn_NextNode->ln_Name));
  2253.  
  2254.                         SHOWMSG("returning the next volume");
  2255.  
  2256.                         strcpy(d->d_name,odn->odn_NextNode->ln_Name);
  2257.  
  2258.                         odn->odn_NextNode = odn->odn_NextNode->ln_Succ;
  2259.  
  2260.                         d->d_ino    = odn->odn_NextDirEntryIndex++;
  2261.                         d->d_namlen    = strlen(d->d_name);
  2262.  
  2263.                         result = d;
  2264.                     }
  2265.                     else
  2266.                     {
  2267.                         errno = 0;
  2268.                     }
  2269.                 }
  2270.             }
  2271.             else
  2272.             {
  2273.                 SHOWMSG("we are reading a user directory");
  2274.  
  2275.                 if(odn->odn_NextDirEntryIndex == 0)
  2276.                 {
  2277.                     SHOWMSG("returning '.'");
  2278.  
  2279.                     /* The first directory entry points
  2280.                      * back to the directory itself.
  2281.                      */
  2282.                     strcpy(d->d_name,".");
  2283.  
  2284.                     d->d_ino    = odn->odn_FIB.fib_DiskKey;
  2285.                     d->d_namlen    = strlen(d->d_name);
  2286.  
  2287.                     odn->odn_NextDirEntryIndex++;
  2288.                     result = d;
  2289.                 }
  2290.                 else if(odn->odn_NextDirEntryIndex == 1)
  2291.                 {
  2292.                     SHOWMSG("returning '..'");
  2293.  
  2294.                     /* The second directory entry points
  2295.                      * to the parent directory.
  2296.                      */
  2297.                     strcpy(d->d_name,"..");
  2298.  
  2299.                     d->d_ino    = odn->odn_ParentDirKey;
  2300.                     d->d_namlen    = strlen(d->d_name);
  2301.  
  2302.                     odn->odn_NextDirEntryIndex++;
  2303.                     result = d;
  2304.                 }
  2305.                 else
  2306.                 {
  2307.                     SHOWMSG("returning next directory entry");
  2308.  
  2309.                     ForbidDOS();
  2310.  
  2311.                     /* All other iterations pick up the
  2312.                      * next following directory entry.
  2313.                      */
  2314.                     if(ExNext(odn->odn_FileLock,&odn->odn_FIB))
  2315.                     {
  2316.                         ASSERT(sizeof(d->d_name) >= strlen(odn->odn_FIB.fib_FileName));
  2317.                         SHOWMSG("got another entry");
  2318.  
  2319.                         strcpy(d->d_name,odn->odn_FIB.fib_FileName);
  2320.  
  2321.                         d->d_ino    = odn->odn_FIB.fib_DiskKey;
  2322.                         d->d_namlen    = strlen(d->d_name);
  2323.  
  2324.                         result = d;
  2325.                     }
  2326.                     else
  2327.                     {
  2328.                         LONG error = IoErr();
  2329.  
  2330.                         if(error == ERROR_NO_MORE_ENTRIES)
  2331.                         {
  2332.                             SHOWMSG("there is no next directory entry.");
  2333.                             errno = 0;
  2334.                         }
  2335.                         else
  2336.                         {
  2337.                             SHOWMSG("some other problem...");
  2338.  
  2339.                             SetIoErr(error);
  2340.                             MapIoErrToErrno();
  2341.                         }
  2342.                     }
  2343.  
  2344.                     PermitDOS();
  2345.                 }
  2346.             }
  2347.         }
  2348.     }
  2349.  
  2350.     if(result != NULL)
  2351.         SHOWSTRING(result->d_name);
  2352.  
  2353.     RETURN(result);
  2354.     return(result);
  2355. }
  2356.  
  2357. /******************************************************************************/
  2358.  
  2359. STATIC int
  2360. TranslateRelativePath(char **namePtr,char *replace,int maxReplaceLen)
  2361. {
  2362.     int result = ERROR;
  2363.     char * name;
  2364.  
  2365.     ENTER();
  2366.  
  2367.     ASSERT(namePtr != NULL && (*namePtr) != NULL && replace != NULL);
  2368.  
  2369.     /* If we have a current directory all references should
  2370.      * be made relative to, do just that. Absolute paths
  2371.      * are not modified, though.
  2372.      */
  2373.     name = (*namePtr);
  2374.     if(NOT STRING_IS_EMPTY(CurrentDirName) && name[0] != '/')
  2375.     {
  2376.         int totalLen;
  2377.  
  2378.         SHOWMSG("Changing the directory name");
  2379.  
  2380.         /* Skip current dir modifiers, we just want the name. */
  2381.         if(strncmp(name,"./",2) == SAME)
  2382.             name += 2;
  2383.         else if (strcmp(name,".") == SAME)
  2384.             name = "";
  2385.  
  2386.         /* Get the current directory name and get
  2387.          * ready to attach the file name at the end.
  2388.          */
  2389.         totalLen = strlen(CurrentDirName);
  2390.  
  2391.         if(CurrentDirName[totalLen-1] != '/' &&
  2392.            CurrentDirName[totalLen-1] != ':' &&
  2393.            NOT STRING_IS_EMPTY(name))
  2394.         {
  2395.             totalLen++;
  2396.         }
  2397.  
  2398.         totalLen += strlen(name);
  2399.  
  2400.         /* Check if the complete string will fit. */
  2401.         if(totalLen < maxReplaceLen)
  2402.         {
  2403.             /* Put the file name together. */
  2404.             strcpy(replace,CurrentDirName);
  2405.             if(CurrentDirName[strlen(CurrentDirName)-1] != '/' && NOT STRING_IS_EMPTY(name))
  2406.                 strcat(replace,"/");
  2407.  
  2408.             strcat(replace,name);
  2409.  
  2410.             (*namePtr) = replace;
  2411.             SHOWSTRING(*namePtr);
  2412.  
  2413.             result = OK;
  2414.         }
  2415.         else
  2416.         {
  2417.             errno = ENAMETOOLONG;
  2418.         }
  2419.     }
  2420.     else
  2421.     {
  2422.         result = OK;
  2423.     }
  2424.  
  2425.     RETURN(result);
  2426.     return(result);
  2427. }
  2428.  
  2429. /******************************************************************************/
  2430.  
  2431. int
  2432. amiga_mkdir(char *name,int mode)
  2433. {
  2434.     struct MangleInfo mi;
  2435.     BPTR dirLock;
  2436.     int result = ERROR;
  2437.  
  2438.     chkabort();
  2439.  
  2440.     ASSERT(name != NULL);
  2441.  
  2442.     ENTER();
  2443.     SHOWSTRING(name);
  2444.     SHOWVALUE(mode);
  2445.  
  2446.     if(MangleName(&name,&mi) == OK)
  2447.     {
  2448.         ForbidDOS();
  2449.  
  2450.         dirLock = CreateDir((STRPTR)name);
  2451.         if(dirLock != ZERO)
  2452.         {
  2453.             UnLock(dirLock);
  2454.             result = OK;
  2455.         }
  2456.         else
  2457.         {
  2458.             MapIoErrToErrno();
  2459.         }
  2460.  
  2461.         PermitDOS();
  2462.  
  2463.         UnmangleName(&name,&mi);
  2464.     }
  2465.  
  2466.     if(result == OK)
  2467.         result = amiga_chmod(name,mode);
  2468.  
  2469.     RETURN(result);
  2470.     return(result);
  2471. }
  2472.  
  2473. /******************************************************************************/
  2474.  
  2475. int
  2476. amiga_rmdir(char *name)
  2477. {
  2478.     struct MangleInfo mi;
  2479.     BPTR fileLock;
  2480.     int result = ERROR;
  2481.  
  2482.     chkabort();
  2483.  
  2484.     ENTER();
  2485.     SHOWSTRING(name);
  2486.  
  2487.     if(MangleName(&name,&mi) == OK)
  2488.     {
  2489.         ForbidDOS();
  2490.  
  2491.         fileLock = Lock(name,SHARED_LOCK);
  2492.         if(fileLock != ZERO)
  2493.         {
  2494.             D_S(struct FileInfoBlock,fib);
  2495.  
  2496.             if(Examine(fileLock,fib))
  2497.             {
  2498.                 UnLock(fileLock);
  2499.                 fileLock = ZERO;
  2500.  
  2501.                 /* Make sure that we get to remove a drawer,
  2502.                  * as the function name implies.
  2503.                  */
  2504.                 if(FIB_IS_DRAWER(fib))
  2505.                 {
  2506.                     if(DeleteFile(name))
  2507.                         result = OK;
  2508.                     else
  2509.                         MapIoErrToErrno();
  2510.                 }
  2511.                 else
  2512.                 {
  2513.                     errno = ENOTDIR;
  2514.                 }
  2515.             }
  2516.             else
  2517.             {
  2518.                 MapIoErrToErrno();
  2519.             }
  2520.  
  2521.             UnLock(fileLock);
  2522.         }
  2523.         else
  2524.         {
  2525.             MapIoErrToErrno();
  2526.         }
  2527.  
  2528.         PermitDOS();
  2529.  
  2530.         UnmangleName(&name,&mi);
  2531.     }
  2532.  
  2533.     RETURN(result);
  2534.     return(result);
  2535. }
  2536.  
  2537. /******************************************************************************/
  2538.  
  2539. int
  2540. amiga_creat(char *name,int prot)
  2541. {
  2542.     struct MangleInfo mi;
  2543.     int result = ERROR;
  2544.  
  2545.     chkabort();
  2546.  
  2547.     ASSERT(name != NULL);
  2548.  
  2549.     ENTER();
  2550.     SHOWSTRING(name);
  2551.     SHOWVALUE(prot);
  2552.  
  2553.     if(MangleName(&name,&mi) == OK)
  2554.     {
  2555.         ForbidDOS();
  2556.         result = creat(name,prot);
  2557.         PermitDOS();
  2558.  
  2559.         UnmangleName(&name,&mi);
  2560.     }
  2561.  
  2562.     RETURN(result);
  2563.     return(result);
  2564. }
  2565.  
  2566. /******************************************************************************/
  2567.  
  2568. FILE *
  2569. amiga_fopen(char *name,char *mode)
  2570. {
  2571.     struct MangleInfo mi;
  2572.     FILE *result = NULL;
  2573.  
  2574.     chkabort();
  2575.  
  2576.     ASSERT(name != NULL && mode != NULL);
  2577.  
  2578.     ENTER();
  2579.     SHOWSTRING(name);
  2580.     SHOWSTRING(mode);
  2581.  
  2582.     if(MangleName(&name,&mi) == OK)
  2583.     {
  2584.         ForbidDOS();
  2585.         result = fopen(name,mode);
  2586.         PermitDOS();
  2587.  
  2588.         UnmangleName(&name,&mi);
  2589.     }
  2590.  
  2591.     RETURN(result);
  2592.     return(result);
  2593. }
  2594.  
  2595. /******************************************************************************/
  2596.  
  2597. int
  2598. amiga_rename(char *old,char *new)
  2599. {
  2600.     struct MangleInfo old_mi;
  2601.     struct MangleInfo new_mi;
  2602.     int result = ERROR;
  2603.  
  2604.     chkabort();
  2605.  
  2606.     ASSERT(old != NULL && new != NULL);
  2607.  
  2608.     ENTER();
  2609.     SHOWSTRING(old);
  2610.     SHOWSTRING(new);
  2611.  
  2612.     /* rename() causes the link named <from> to be renamed as <to>. If <to> exists,
  2613.      * it is first removed. Both <from> and <to> must be of the same type (that is,
  2614.      * both directories or both non-directories), and must reside on the same
  2615.      * file system.
  2616.      */
  2617.  
  2618.     if(MangleName(&old,&old_mi) == OK)
  2619.     {
  2620.         if(MangleName(&new,&new_mi) == OK)
  2621.         {
  2622.             ForbidDOS();
  2623.  
  2624.             D(("rename |%s| to |%s|",old,new));
  2625.  
  2626.             if(CANNOT Rename(old,new))
  2627.             {
  2628.                 LONG error = IoErr();
  2629.  
  2630.                 SHOWVALUE(error);
  2631.  
  2632.                 if(error == ERROR_OBJECT_EXISTS)
  2633.                 {
  2634.                     BPTR oldLock = Lock(old,SHARED_LOCK);
  2635.                     BPTR newLock = Lock(new,SHARED_LOCK);
  2636.  
  2637.                     if(oldLock != ZERO && newLock != ZERO && SameLock(oldLock,newLock) == LOCK_SAME)
  2638.                     {
  2639.                         result = OK;
  2640.                         error = OK;
  2641.  
  2642.                         SHOWMSG("Ok; same name");
  2643.  
  2644.                         UnLock(oldLock);
  2645.                         UnLock(newLock);
  2646.                     }
  2647.                     else
  2648.                     {
  2649.                         UnLock(oldLock);
  2650.                         UnLock(newLock);
  2651.  
  2652.                         if(DeleteFile(new))
  2653.                         {
  2654.                             if(Rename(old,new))
  2655.                             {
  2656.                                 result = OK;
  2657.                                 error = OK;
  2658.  
  2659.                                 SHOWMSG("Ok; after removing");
  2660.                             }
  2661.                             else
  2662.                             {
  2663.                                 error = IoErr();
  2664.                             }
  2665.                         }
  2666.                         else
  2667.                         {
  2668.                             error = IoErr();
  2669.                         }
  2670.                     }
  2671.                 }
  2672.  
  2673.                 if(error != OK)
  2674.                 {
  2675.                     SHOWVALUE(error);
  2676.  
  2677.                     SetIoErr(error);
  2678.                     MapIoErrToErrno();
  2679.                 }
  2680.             }
  2681.             else
  2682.             {
  2683.                 SHOWMSG("Ok");
  2684.  
  2685.                 result = OK;
  2686.             }
  2687.  
  2688.             PermitDOS();
  2689.  
  2690.             UnmangleName(&new,&new_mi);
  2691.         }
  2692.         else
  2693.         {
  2694.             SHOWMSG("MangleName new_mi failed");
  2695.         }
  2696.  
  2697.         UnmangleName(&old,&old_mi);
  2698.     }
  2699.     else
  2700.     {
  2701.         SHOWMSG("MangleName old_mi failed");
  2702.     }
  2703.  
  2704.     RETURN(result);
  2705.     return(result);
  2706. }
  2707.  
  2708. /******************************************************************************/
  2709.  
  2710. char *
  2711. amiga_getcwd(char *buf, size_t size)
  2712. {
  2713.     char *result = NULL;
  2714.  
  2715.     chkabort();
  2716.  
  2717.     ASSERT(buf != NULL);
  2718.  
  2719.     ENTER();
  2720.     SHOWVALUE(buf);
  2721.     SHOWVALUE(size);
  2722.  
  2723.     if(CurrentDirName[0] == '/')
  2724.     {
  2725.         strncpy(buf,CurrentDirName,size-1);
  2726.         buf[size-1] = '\0';
  2727.         result = buf;
  2728.     }
  2729.     else
  2730.     {
  2731.         BPTR oldDir;
  2732.  
  2733.         ForbidDOS();
  2734.  
  2735.         oldDir = CurrentDir(ZERO);
  2736.  
  2737.         if(NameFromLock(oldDir,buf,size))
  2738.         {
  2739.             if(MapFileNameAmigaToUnix(buf,buf,size) == OK)
  2740.                 result = buf;
  2741.         }
  2742.         else
  2743.         {
  2744.             MapIoErrToErrno();
  2745.         }
  2746.  
  2747.         CurrentDir(oldDir);
  2748.  
  2749.         PermitDOS();
  2750.     }
  2751.  
  2752.     SHOWSTRING(result);
  2753.  
  2754.     RETURN(result);
  2755.     return(result);
  2756. }
  2757.  
  2758. /******************************************************************************/
  2759.  
  2760. #define SET_FILESIZE_ERROR (-1)
  2761.  
  2762. int
  2763. amiga_ftruncate(int fd,off_t size)
  2764. {
  2765.     struct UFB * ufb;
  2766.     int result = ERROR;
  2767.  
  2768.     chkabort();
  2769.  
  2770.     ENTER();
  2771.     SHOWVALUE(fd);
  2772.     SHOWVALUE(size);
  2773.  
  2774.     ufb = chkufb(fd);
  2775.     if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  2776.     {
  2777.         ForbidDOS();
  2778.  
  2779.         if(SetFileSize((BPTR)ufb->ufbfh,size,OFFSET_BEGINNING) != SET_FILESIZE_ERROR)
  2780.             result = OK;
  2781.         else
  2782.             MapIoErrToErrno();
  2783.  
  2784.         PermitDOS();
  2785.     }
  2786.     else
  2787.     {
  2788.         errno = EBADF;
  2789.     }
  2790.  
  2791.     RETURN(result);
  2792.     return(result);
  2793. }
  2794.  
  2795. /******************************************************************************/
  2796.  
  2797. int
  2798. amiga_accept(int sockfd,struct sockaddr *cliaddr,int *addrlen)
  2799. {
  2800.     struct UFB * ufb;
  2801.     int result = ERROR;
  2802.  
  2803.     chkabort();
  2804.  
  2805.     ASSERT(cliaddr != NULL && addrlen != NULL);
  2806.  
  2807.     ENTER();
  2808.     SHOWVALUE(sockfd);
  2809.     SHOWVALUE(cliaddr);
  2810.     SHOWVALUE(addrlen);
  2811.  
  2812.     ufb = chkufb(sockfd);
  2813.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2814.         result = accept(ufb->ufbfh,cliaddr,(LONG *)addrlen);
  2815.     else
  2816.         errno = ENOTSOCK;
  2817.  
  2818.     RETURN(result);
  2819.     return(result);
  2820. }
  2821.  
  2822. /******************************************************************************/
  2823.  
  2824. int
  2825. amiga_bind(int sockfd,struct sockaddr *name,int namelen)
  2826. {
  2827.     struct UFB * ufb;
  2828.     int result = ERROR;
  2829.  
  2830.     chkabort();
  2831.  
  2832.     ASSERT(name != NULL);
  2833.  
  2834.     ENTER();
  2835.     SHOWVALUE(sockfd);
  2836.     SHOWVALUE(name);
  2837.     SHOWVALUE(namelen);
  2838.  
  2839.     ufb = chkufb(sockfd);
  2840.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2841.         result = bind(ufb->ufbfh,name,namelen);
  2842.     else
  2843.         errno = ENOTSOCK;
  2844.  
  2845.     RETURN(result);
  2846.     return(result);
  2847. }
  2848.  
  2849. /******************************************************************************/
  2850.  
  2851. int
  2852. amiga_close(int fd)
  2853. {
  2854.     struct UFB * ufb;
  2855.     int result = ERROR;
  2856.  
  2857.     chkabort();
  2858.  
  2859.     ENTER();
  2860.     SHOWVALUE(fd);
  2861.  
  2862.     ufb = chkufb(fd);
  2863.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2864.     {
  2865.         result = CloseSocket(ufb->ufbfh);
  2866.         CLEAR_FLAG(ufb->ufbflg,UFB_IS_SOCKET);
  2867.  
  2868.         /* Make sure that the descriptor looks like a file again. */
  2869.         RestoreDescriptor(ufb);
  2870.  
  2871.         close(fd);
  2872.     }
  2873.     else
  2874.     {
  2875.         if(ufb != NULL)
  2876.         {
  2877.             /* Don't close the stdio streams! */
  2878.             if(fd == 0 || fd == 1 || fd == 2)
  2879.             {
  2880.                 D(("Attempt to muck with fd #%ld!",fd));
  2881.  
  2882.                 errno = EBADF;
  2883.             }
  2884.             else
  2885.             {
  2886.                 char fileName[MAX_FILENAME_LEN];
  2887.                 BOOL removeIt = FALSE;
  2888.  
  2889.                 if(FLAG_IS_SET(ufb->ufbflg,UFB_UNLINK))
  2890.                 {
  2891.                     removeIt = NameFromFH((BPTR)ufb->ufbfh,fileName,sizeof(fileName));
  2892.  
  2893.                     CLEAR_FLAG(ufb->ufbflg,UFB_UNLINK);
  2894.                 }
  2895.  
  2896.                 CleanupFileLocks(fd);
  2897.  
  2898.                 result = close(fd);
  2899.  
  2900.                 if(removeIt)
  2901.                     DeleteFile(fileName);
  2902.             }
  2903.         }
  2904.         else
  2905.         {
  2906.             errno = EBADF;
  2907.         }
  2908.     }
  2909.  
  2910.     RETURN(result);
  2911.     return(result);
  2912. }
  2913.  
  2914. /******************************************************************************/
  2915.  
  2916. int
  2917. amiga_connect(int sockfd,struct sockaddr *name,int namelen)
  2918. {
  2919.     struct UFB * ufb;
  2920.     int result = ERROR;
  2921.  
  2922.     chkabort();
  2923.  
  2924.     ASSERT(name != NULL && namelen > 0);
  2925.  
  2926.     ENTER();
  2927.     SHOWVALUE(sockfd);
  2928.     SHOWVALUE(name);
  2929.     SHOWVALUE(namelen);
  2930.  
  2931.     ufb = chkufb(sockfd);
  2932.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2933.         result = connect(ufb->ufbfh,name,namelen);
  2934.     else
  2935.         errno = ENOTSOCK;
  2936.  
  2937.     RETURN(result);
  2938.     return(result);
  2939. }
  2940.  
  2941. /******************************************************************************/
  2942.  
  2943. int
  2944. amiga_getpeername(int sockfd,struct sockaddr *name,int *namelen)
  2945. {
  2946.     struct UFB * ufb;
  2947.     int result = ERROR;
  2948.  
  2949.     chkabort();
  2950.  
  2951.     ASSERT(name != NULL && namelen != NULL);
  2952.  
  2953.     ENTER();
  2954.     SHOWVALUE(sockfd);
  2955.     SHOWVALUE(name);
  2956.     SHOWVALUE(namelen);
  2957.  
  2958.     ufb = chkufb(sockfd);
  2959.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2960.         result = getpeername(ufb->ufbfh,name,(LONG *)namelen);
  2961.     else
  2962.         errno = ENOTSOCK;
  2963.  
  2964.     RETURN(result);
  2965.     return(result);
  2966. }
  2967.  
  2968. /******************************************************************************/
  2969.  
  2970. int
  2971. amiga_getsockopt(int sockfd,int level,int optname,VOID *optval,int *optlen)
  2972. {
  2973.     struct UFB * ufb;
  2974.     int result = ERROR;
  2975.  
  2976.     chkabort();
  2977.  
  2978.     ASSERT(optval != NULL && optlen != NULL);
  2979.  
  2980.     ENTER();
  2981.     SHOWVALUE(sockfd);
  2982.     SHOWVALUE(level);
  2983.     SHOWVALUE(optname);
  2984.     SHOWVALUE(optval);
  2985.     SHOWVALUE(optlen);
  2986.  
  2987.     ufb = chkufb(sockfd);
  2988.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  2989.         result = getsockopt(ufb->ufbfh,level,optname,optval,(LONG *)optlen);
  2990.     else
  2991.         errno = ENOTSOCK;
  2992.  
  2993.     RETURN(result);
  2994.     return(result);
  2995. }
  2996.  
  2997. /******************************************************************************/
  2998.  
  2999. int
  3000. amiga_ioctl(int fd,unsigned long request,char *arg)
  3001. {
  3002.     struct UFB * ufb;
  3003.     int result = ERROR;
  3004.  
  3005.     chkabort();
  3006.  
  3007.     ASSERT(arg != NULL);
  3008.  
  3009.     ENTER();
  3010.     SHOWVALUE(fd);
  3011.     SHOWVALUE(request);
  3012.     SHOWVALUE(arg);
  3013.  
  3014.     ufb = chkufb(fd);
  3015.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3016.         result = IoctlSocket(ufb->ufbfh,request,arg);
  3017.     else
  3018.         errno = ENOTSOCK;
  3019.  
  3020.     RETURN(result);
  3021.     return(result);
  3022. }
  3023.  
  3024. /******************************************************************************/
  3025.  
  3026. int
  3027. amiga_listen(int sockfd,int backlog)
  3028. {
  3029.     struct UFB * ufb;
  3030.     int result = ERROR;
  3031.  
  3032.     chkabort();
  3033.  
  3034.     ENTER();
  3035.     SHOWVALUE(sockfd);
  3036.     SHOWVALUE(backlog);
  3037.  
  3038.     ufb = chkufb(sockfd);
  3039.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3040.         result = listen(ufb->ufbfh,backlog);
  3041.     else
  3042.         errno = ENOTSOCK;
  3043.  
  3044.     RETURN(result);
  3045.     return(result);
  3046. }
  3047.  
  3048. /******************************************************************************/
  3049.  
  3050. int
  3051. amiga_read(int fd,VOID *data,unsigned int size)
  3052. {
  3053.     struct UFB * ufb;
  3054.     int result;
  3055.  
  3056.     chkabort();
  3057.  
  3058.     ASSERT(data != NULL);
  3059.  
  3060.     ENTER();
  3061.     SHOWVALUE(fd);
  3062.     SHOWVALUE(data);
  3063.     SHOWVALUE(size);
  3064.  
  3065.     ufb = chkufb(fd);
  3066.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3067.     {
  3068.         SHOWMSG("input from socket");
  3069.         result = recv(ufb->ufbfh,data,size,0);
  3070.     }
  3071.     else
  3072.     {
  3073.         SHOWMSG("input from file");
  3074.         ForbidDOS();
  3075.         result = read(fd,data,size);
  3076.         PermitDOS();
  3077.     }
  3078.  
  3079.     RETURN(result);
  3080.     return(result);
  3081. }
  3082.  
  3083. /******************************************************************************/
  3084.  
  3085. int
  3086. amiga_recvfrom(int sockfd,VOID *buff,int len,int flags,struct sockaddr *from,int *fromlen)
  3087. {
  3088.     struct UFB * ufb;
  3089.     int result = ERROR;
  3090.  
  3091.     chkabort();
  3092.  
  3093.     ASSERT(buff != NULL && from != NULL && fromlen != NULL);
  3094.  
  3095.     ENTER();
  3096.     SHOWVALUE(sockfd);
  3097.     SHOWVALUE(buff);
  3098.     SHOWVALUE(len);
  3099.     SHOWVALUE(flags);
  3100.     SHOWVALUE(from);
  3101.     SHOWVALUE(fromlen);
  3102.  
  3103.     ufb = chkufb(sockfd);
  3104.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3105.         result = recvfrom(ufb->ufbfh,buff,len,flags,from,(LONG *)fromlen);
  3106.     else
  3107.         errno = ENOTSOCK;
  3108.  
  3109.     RETURN(result);
  3110.     return(result);
  3111. }
  3112.  
  3113. /******************************************************************************/
  3114.  
  3115. STATIC VOID
  3116. MapDescriptorSets(
  3117.     const fd_set *    input_fds,
  3118.     int                num_input_fds,
  3119.     fd_set *        socket_fds,
  3120.     int *            max_socket_fd_ptr,
  3121.     fd_set *        file_fds,
  3122.     int *            max_file_fd_ptr)
  3123. {
  3124.     FD_ZERO(socket_fds);
  3125.     FD_ZERO(file_fds);
  3126.  
  3127.     /* This routine maps file descriptor sets
  3128.      * from one format to another. We map
  3129.      * socket descriptors and regular file
  3130.      * descriptor sets.
  3131.      */
  3132.     if(input_fds != NULL && num_input_fds > 0)
  3133.     {
  3134.         int max_socket_fd = (*max_socket_fd_ptr);
  3135.         int max_file_fd = (*max_file_fd_ptr);
  3136.         struct UFB * ufb;
  3137.         int i;
  3138.  
  3139.         for(i = 0 ; i < num_input_fds ; i++)
  3140.         {
  3141.             if(FD_ISSET(i,input_fds))
  3142.             {
  3143.                 D(("fd to wait on #%ld",i));
  3144.  
  3145.                 ufb = chkufb(i);
  3146.                 if(ufb != NULL)
  3147.                 {
  3148.                     /* Is this a socket descriptor? */
  3149.                     if(FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3150.                     {
  3151.                         D(("fd #%ld is a socket.\n",i));
  3152.  
  3153.                         FD_SET(ufb->ufbfh,socket_fds);
  3154.  
  3155.                         if(max_socket_fd < ufb->ufbfh)
  3156.                             max_socket_fd = ufb->ufbfh;
  3157.                     }
  3158.                     else
  3159.                     {
  3160.                         D(("fd #%ld is a file.\n",i));
  3161.  
  3162.                         /* We only watch files bound to
  3163.                          * console streams.
  3164.                          */
  3165.                         if(IsInteractive((BPTR)ufb->ufbfh))
  3166.                         {
  3167.                             FD_SET(i,file_fds);
  3168.  
  3169.                             if(max_file_fd < i)
  3170.                                 max_file_fd = i;
  3171.                         }
  3172.                     }
  3173.                 }
  3174.             }
  3175.         }
  3176.  
  3177.         (*max_socket_fd_ptr)    = max_socket_fd;
  3178.         (*max_file_fd_ptr)        = max_file_fd;
  3179.     }
  3180. }
  3181.  
  3182. STATIC VOID
  3183. RemapDescriptorSets(
  3184.     const fd_set *    socket_fds,
  3185.     int                max_socket_fd,
  3186.     const fd_set *    file_fds,
  3187.     int                max_file_fd,
  3188.     fd_set *        output_fds,
  3189.     int                num_output_fds)
  3190. {
  3191.     /* This routine reverses the mapping established
  3192.      * above. We map the file and socket descriptor
  3193.      * sets back into the original set.
  3194.      */
  3195.     if(output_fds != NULL)
  3196.     {
  3197.         int fd;
  3198.  
  3199.         FD_ZERO(output_fds);
  3200.  
  3201.         for(fd = 0 ; fd <= max_socket_fd ; fd++)
  3202.         {
  3203.             if(FD_ISSET(fd,socket_fds))
  3204.             {
  3205.                 struct UFB * ufb;
  3206.                 int output_fd;
  3207.  
  3208.                 for(output_fd = 0 ; output_fd < num_output_fds ; output_fd++)
  3209.                 {
  3210.                     ufb = chkufb(output_fd);
  3211.                     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET) && ufb->ufbfh == fd)
  3212.                     {
  3213.                         D(("fd #%ld has data",output_fd));
  3214.                         FD_SET(output_fd,output_fds);
  3215.                         break;
  3216.                     }
  3217.                 }
  3218.             }
  3219.         }
  3220.  
  3221.         for(fd = 0 ; fd <= max_file_fd ; fd++)
  3222.         {
  3223.             if(FD_ISSET(fd,file_fds))
  3224.             {
  3225.                 D(("fd #%ld has data",fd));
  3226.                 FD_SET(fd,output_fds);
  3227.             }
  3228.         }
  3229.     }
  3230. }
  3231.  
  3232. int
  3233. amiga_select(int num_fds,fd_set *read_fds,fd_set *write_fds,fd_set *except_fds,struct timeval *timeout)
  3234. {
  3235.     fd_set socket_read_fds;
  3236.     fd_set socket_write_fds;
  3237.     fd_set socket_except_fds;
  3238.     int max_socket_fd;
  3239.     fd_set file_read_fds;
  3240.     fd_set file_write_fds;
  3241.     fd_set file_except_fds;
  3242.     struct UFB * ufb;
  3243.     int max_file_fd;
  3244.     int result = 0;
  3245.  
  3246.     chkabort();
  3247.  
  3248.     ENTER();
  3249.  
  3250.     if(num_fds > FD_SETSIZE)
  3251.     {
  3252.         D(("Warning: %ld descriptor sets to wait on requested; only %ld available.",num_fds,FD_SETSIZE));
  3253.         num_fds = FD_SETSIZE;
  3254.     }
  3255.  
  3256.     max_socket_fd = -1;
  3257.     max_file_fd = -1;
  3258.  
  3259.     MapDescriptorSets(read_fds,        num_fds,    &socket_read_fds,    &max_socket_fd,    &file_read_fds,        &max_file_fd);
  3260.     MapDescriptorSets(write_fds,    num_fds,    &socket_write_fds,    &max_socket_fd,    &file_write_fds,    &max_file_fd);
  3261.     MapDescriptorSets(except_fds,    num_fds,    &socket_except_fds,    &max_socket_fd,    &file_except_fds,    &max_file_fd);
  3262.  
  3263.     D(("number of socket fds to work on == %ld",max_socket_fd+1));
  3264.     D(("number of file   fds to work on == %ld",max_file_fd+1));
  3265.  
  3266.     /* Wait for socket input? */
  3267.     if(max_socket_fd != -1)
  3268.     {
  3269.         /* Wait for file input, too? */
  3270.         if(max_file_fd != -1 && (timeout == NULL || timeout->tv_secs > 0 || timeout->tv_micro > 0))
  3271.         {
  3272.             struct timeval stopWhen;
  3273.             struct timeval zero;
  3274.             BOOL gotSomething;
  3275.             ULONG breakMask;
  3276.             int i;
  3277.  
  3278.             /* We are going to poll all streams; for the timeout
  3279.              * feature to work, we absolutely must know when to
  3280.              * stop polling.
  3281.              *
  3282.              * Why aren't we using asynchronous DOS packets?
  3283.              * The answer is that once a packet is sent, you
  3284.              * cannot easily abort it. Polling is safer in
  3285.              * that respect. Yes, I know that ACTION_STACK
  3286.              * can be used to fake input to a console stream,
  3287.              * but I'd rather not rely upon it.
  3288.              */
  3289.             if(timeout != NULL)
  3290.             {
  3291.                 GetSysTime((APTR)&stopWhen);
  3292.                 AddTime((APTR)&stopWhen,(APTR)timeout);
  3293.             }
  3294.             else
  3295.             {
  3296.                 /* No timeout, poll until we are interrupted
  3297.                  * or get input from any of the files. It's
  3298.                  * not really necessary to initialize this
  3299.                  * timeval, but it keeps the compiler happy.
  3300.                  */
  3301.                 memset(&stopWhen,0,sizeof(stopWhen));
  3302.             }
  3303.  
  3304.             while(TRUE)
  3305.             {
  3306.                 /* Check for break signal. */
  3307.                 chkabort();
  3308.  
  3309.                 /* Delay for a tick to avoid busy-waiting. */
  3310.                 Delay(1);
  3311.  
  3312.                 /* This tells WaitSelect() to poll the sockets for input. */
  3313.                 zero.tv_secs    = 0;
  3314.                 zero.tv_micro    = 0;
  3315.  
  3316.                 /* Signals to stop on; we want to stop when a break signal arrives. */
  3317.                 if(AllowBreak)
  3318.                     breakMask = SIGBREAKF_CTRL_C;
  3319.                 else
  3320.                     breakMask = 0;
  3321.  
  3322.                 /* Check for socket input. */
  3323.                 result = WaitSelect(max_socket_fd+1,&socket_read_fds,&socket_write_fds,&socket_except_fds,&zero,&breakMask);
  3324.  
  3325.                 /* Stop if a break signal arrives. */
  3326.                 if((result < 0 && errno == EINTR) || FLAG_IS_SET(breakMask,SIGBREAKF_CTRL_C))
  3327.                     raise(SIGINT);
  3328.  
  3329.                 /* Stop if the return value from WaitSelect is negative. */
  3330.                 if(result < 0)
  3331.                     break;
  3332.  
  3333.                 /* Did we get any socket input? */
  3334.                 gotSomething = (BOOL)(result > 0);
  3335.                 if(NOT gotSomething)
  3336.                 {
  3337.                     /* Check all files for input. We also poll
  3338.                      * them for input, but each with a little
  3339.                      * delay of about 1/50 of a second. We stop
  3340.                      * as soon as we find one file that has
  3341.                      * input in it.
  3342.                      */
  3343.                     for(i = 0 ; i <= max_file_fd ; i++)
  3344.                     {
  3345.                         if(FD_ISSET(i,&file_read_fds) ||
  3346.                            FD_ISSET(i,&file_write_fds) ||
  3347.                            FD_ISSET(i,&file_except_fds))
  3348.                         {
  3349.                             ufb = chkufb(i);
  3350.                             if(ufb != NULL)
  3351.                             {
  3352.                                 if(WaitForChar((BPTR)ufb->ufbfh,1))
  3353.                                 {
  3354.                                     gotSomething = TRUE;
  3355.                                     break;
  3356.                                 }
  3357.                             }
  3358.                         }
  3359.                     }
  3360.                 }
  3361.  
  3362.                 /* Did we get any input at all? */
  3363.                 if(gotSomething)
  3364.                 {
  3365.                     BOOL gotInput;
  3366.  
  3367.                     /* Now retest all files and remember
  3368.                      * those that had input.
  3369.                      */
  3370.                     for(i = 0 ; i <= max_file_fd ; i++)
  3371.                     {
  3372.                         gotInput = FALSE;
  3373.  
  3374.                         if(FD_ISSET(i,&file_read_fds) ||
  3375.                            FD_ISSET(i,&file_write_fds) ||
  3376.                            FD_ISSET(i,&file_except_fds))
  3377.                         {
  3378.                             ufb = chkufb(i);
  3379.                             if(ufb != NULL)
  3380.                             {
  3381.                                 /* Does this one have input? */
  3382.                                 gotInput = WaitForChar((BPTR)ufb->ufbfh,1);
  3383.                             }
  3384.                         }
  3385.  
  3386.                         if(gotInput)
  3387.                         {
  3388.                             /* Mark one more descriptor as
  3389.                              * having input.
  3390.                              */
  3391.                             result++;
  3392.                         }
  3393.                         else
  3394.                         {
  3395.                             /* Mark this descriptor as
  3396.                              * not having any input.
  3397.                              */
  3398.                             FD_CLR(i,&file_read_fds);
  3399.                             FD_CLR(i,&file_write_fds);
  3400.                             FD_CLR(i,&file_except_fds);
  3401.                         }
  3402.                     }
  3403.                 }
  3404.  
  3405.                 /* Did we get any input? If so, stop polling. */
  3406.                 if(result > 0)
  3407.                     break;
  3408.  
  3409.                 /* If a timeout was set, check if we are already
  3410.                  * beyond the point of time when we should have
  3411.                  * stopped polling.
  3412.                  */
  3413.                 if(timeout != NULL)
  3414.                 {
  3415.                     struct timeval now;
  3416.  
  3417.                     GetSysTime((APTR)&now);
  3418.  
  3419.                     if((-CmpTime((APTR)&now,(APTR)&stopWhen)) >= 0)
  3420.                         break;
  3421.                 }
  3422.             }
  3423.         }
  3424.         else
  3425.         {
  3426.             ULONG breakMask;
  3427.  
  3428.             if(AllowBreak)
  3429.                 breakMask = SIGBREAKF_CTRL_C;
  3430.             else
  3431.                 breakMask = 0;
  3432.  
  3433.             result = WaitSelect(max_socket_fd+1,&socket_read_fds,&socket_write_fds,&socket_except_fds,timeout,&breakMask);
  3434.             if((result < 0 && errno == EINTR) || FLAG_IS_SET(breakMask,SIGBREAKF_CTRL_C))
  3435.                 raise(SIGINT);
  3436.         }
  3437.     }
  3438.     else
  3439.     {
  3440.         /* Wait for file input? */
  3441.         if(max_file_fd != -1 && (timeout == NULL || timeout->tv_secs > 0 || timeout->tv_micro > 0))
  3442.         {
  3443.             struct timeval stopWhen;
  3444.             BOOL gotSomething;
  3445.             int i;
  3446.  
  3447.             if(timeout != NULL)
  3448.             {
  3449.                 GetSysTime((APTR)&stopWhen);
  3450.                 AddTime((APTR)&stopWhen,(APTR)timeout);
  3451.             }
  3452.             else
  3453.             {
  3454.                 memset(&stopWhen,0,sizeof(stopWhen));
  3455.             }
  3456.  
  3457.             while(TRUE)
  3458.             {
  3459.                 chkabort();
  3460.  
  3461.                 Delay(1);
  3462.  
  3463.                 gotSomething = FALSE;
  3464.                 for(i = 0 ; i <= max_file_fd ; i++)
  3465.                 {
  3466.                     if(FD_ISSET(i,&file_read_fds) ||
  3467.                        FD_ISSET(i,&file_write_fds) ||
  3468.                        FD_ISSET(i,&file_except_fds))
  3469.                     {
  3470.                         ufb = chkufb(i);
  3471.                         if(ufb != NULL)
  3472.                         {
  3473.                             if(WaitForChar((BPTR)ufb->ufbfh,1))
  3474.                             {
  3475.                                 gotSomething = TRUE;
  3476.                                 break;
  3477.                             }
  3478.                         }
  3479.                     }
  3480.                 }
  3481.  
  3482.                 if(gotSomething)
  3483.                 {
  3484.                     BOOL gotInput;
  3485.  
  3486.                     for(i = 0 ; i <= max_file_fd ; i++)
  3487.                     {
  3488.                         gotInput = FALSE;
  3489.  
  3490.                         if(FD_ISSET(i,&file_read_fds) ||
  3491.                            FD_ISSET(i,&file_write_fds) ||
  3492.                            FD_ISSET(i,&file_except_fds))
  3493.                         {
  3494.                             ufb = chkufb(i);
  3495.                             if(ufb != NULL)
  3496.                             {
  3497.                                 /* Does this one have input? */
  3498.                                 gotInput = WaitForChar((BPTR)ufb->ufbfh,1);
  3499.                             }
  3500.                         }
  3501.  
  3502.                         if(gotInput)
  3503.                         {
  3504.                             result++;
  3505.                         }
  3506.                         else
  3507.                         {
  3508.                             FD_CLR(i,&file_read_fds);
  3509.                             FD_CLR(i,&file_write_fds);
  3510.                             FD_CLR(i,&file_except_fds);
  3511.                         }
  3512.                     }
  3513.                 }
  3514.  
  3515.                 if(result > 0)
  3516.                     break;
  3517.  
  3518.                 if(timeout != NULL)
  3519.                 {
  3520.                     struct timeval now;
  3521.  
  3522.                     GetSysTime((APTR)&now);
  3523.  
  3524.                     if((-CmpTime((APTR)&now,(APTR)&stopWhen)) >= 0)
  3525.                         break;
  3526.                 }
  3527.             }
  3528.         }
  3529.     }
  3530.  
  3531.     /* The descriptor sets remain unchanged in
  3532.      * case of error.
  3533.      */
  3534.     if(result >= 0)
  3535.     {
  3536.         RemapDescriptorSets(&socket_read_fds,    max_socket_fd,    &file_read_fds,        max_file_fd,    read_fds,    num_fds);
  3537.         RemapDescriptorSets(&socket_write_fds,    max_socket_fd,    &file_write_fds,    max_file_fd,    write_fds,    num_fds);
  3538.         RemapDescriptorSets(&socket_except_fds,    max_socket_fd,    &file_except_fds,    max_file_fd,    except_fds,    num_fds);
  3539.     }
  3540.  
  3541.     RETURN(result);
  3542.     return(result);
  3543. }
  3544.  
  3545. /******************************************************************************/
  3546.  
  3547. int
  3548. amiga_sendto(int sockfd,VOID *buff,int len,int flags,struct sockaddr *to,int tolen)
  3549. {
  3550.     struct UFB * ufb;
  3551.     int result = ERROR;
  3552.  
  3553.     chkabort();
  3554.  
  3555.     ASSERT(buff != NULL && to != NULL);
  3556.  
  3557.     ENTER();
  3558.     SHOWVALUE(sockfd);
  3559.     SHOWVALUE(buff);
  3560.     SHOWVALUE(len);
  3561.     SHOWVALUE(flags);
  3562.     SHOWVALUE(to);
  3563.     SHOWVALUE(tolen);
  3564.  
  3565.     ufb = chkufb(sockfd);
  3566.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3567.         result = sendto(ufb->ufbfh,buff,len,flags,to,tolen);
  3568.     else
  3569.         errno = ENOTSOCK;
  3570.  
  3571.     RETURN(result);
  3572.     return(result);
  3573. }
  3574.  
  3575. /******************************************************************************/
  3576.  
  3577. int
  3578. amiga_setsockopt(int sockfd,int level,int optname,VOID *optval,int optlen)
  3579. {
  3580.     struct UFB * ufb;
  3581.     int result = ERROR;
  3582.  
  3583.     chkabort();
  3584.  
  3585.     ASSERT(optval != NULL);
  3586.  
  3587.     ENTER();
  3588.     SHOWVALUE(sockfd);
  3589.     SHOWVALUE(level);
  3590.     SHOWVALUE(optname);
  3591.     SHOWVALUE(optval);
  3592.     SHOWVALUE(optlen);
  3593.  
  3594.     ufb = chkufb(sockfd);
  3595.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3596.         result = setsockopt(ufb->ufbfh,level,optname,optval,optlen);
  3597.     else
  3598.         errno = ENOTSOCK;
  3599.  
  3600.     RETURN(result);
  3601.     return(result);
  3602. }
  3603.  
  3604. /******************************************************************************/
  3605.  
  3606. int
  3607. amiga_socket(int domain,int type,int protocol)
  3608. {
  3609.     int result = ERROR;
  3610.     int fd;
  3611.  
  3612.     chkabort();
  3613.  
  3614.     ENTER();
  3615.     SHOWVALUE(domain);
  3616.     SHOWVALUE(type);
  3617.     SHOWVALUE(protocol);
  3618.  
  3619.     /* We open a regular file that is guaranteed to
  3620.      * open in any case and then attach a socket
  3621.      * in place of the original file handle.
  3622.      */
  3623.     fd = open("NIL:",O_RDWR,0777);
  3624.     if(fd != -1)
  3625.     {
  3626.         struct UFB * ufb;
  3627.  
  3628.         ufb = chkufb(fd);
  3629.         if(ufb != NULL)
  3630.         {
  3631.             /* Save the original file handle value. */
  3632.             if(SaveDescriptor(ufb))
  3633.             {
  3634.                 int sockfd;
  3635.  
  3636.                 /* Now create the real socket. */
  3637.                 sockfd = socket(domain,type,protocol);
  3638.                 if(sockfd != -1)
  3639.                 {
  3640.                     /* Put the socket in place of the file handle. */
  3641.                     SET_FLAG(ufb->ufbflg,UFB_IS_SOCKET);
  3642.                     ufb->ufbfh = sockfd;
  3643.  
  3644.                     result = fd;
  3645.                 }
  3646.                 else
  3647.                 {
  3648.                     close(fd);
  3649.                 }
  3650.             }
  3651.             else
  3652.             {
  3653.                 close(fd);
  3654.                 errno = ENOMEM;
  3655.             }
  3656.         }
  3657.         else
  3658.         {
  3659.             close(fd);
  3660.             errno = EBADF;
  3661.         }
  3662.     }
  3663.  
  3664.     RETURN(result);
  3665.     return(result);
  3666. }
  3667.  
  3668. /******************************************************************************/
  3669.  
  3670. int
  3671. amiga_write(int fd,VOID *data,unsigned int size)
  3672. {
  3673.     struct UFB * ufb;
  3674.     int result;
  3675.  
  3676.     chkabort();
  3677.  
  3678.     ASSERT(data != NULL);
  3679.  
  3680.     ENTER();
  3681.     SHOWVALUE(fd);
  3682.     SHOWVALUE(data);
  3683.     SHOWVALUE(size);
  3684.  
  3685.     ufb = chkufb(fd);
  3686.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3687.     {
  3688.         result = send(ufb->ufbfh,data,size,0);
  3689.     }
  3690.     else
  3691.     {
  3692.         ForbidDOS();
  3693.         result = write(fd,data,size);
  3694.         PermitDOS();
  3695.     }
  3696.  
  3697.     RETURN(result);
  3698.     return(result);
  3699. }
  3700.  
  3701. /******************************************************************************/
  3702.  
  3703. STATIC VOID
  3704. ConvertFileInfoToStat(
  3705.     struct MsgPort * port,
  3706.     struct FileInfoBlock * fib,
  3707.     struct stat * st)
  3708. {
  3709.     ULONG flags;
  3710.     int mode;
  3711.     long time;
  3712.  
  3713.     /* This routine converts the contents of a FileInfoBlock
  3714.      * into information to fill a Unix-like stat data structure
  3715.      * with.
  3716.      */
  3717.     flags = fib->fib_Protection ^ (FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
  3718.  
  3719.     if(FIB_IS_DRAWER(fib))
  3720.         mode = S_IFDIR;
  3721.     else
  3722.         mode = S_IFREG;
  3723.  
  3724.     if(FLAG_IS_SET(flags,FIBF_READ))
  3725.         SET_FLAG(mode,S_IRUSR);
  3726.  
  3727.     if(FLAG_IS_SET(flags,FIBF_WRITE) && FLAG_IS_SET(flags,FIBF_DELETE))
  3728.         SET_FLAG(mode,S_IWUSR);
  3729.  
  3730.     if(FLAG_IS_SET(flags,FIBF_EXECUTE))
  3731.         SET_FLAG(mode,S_IXUSR);
  3732.  
  3733.  
  3734.     if(FLAG_IS_SET(flags,FIBF_GRP_READ))
  3735.         SET_FLAG(mode,S_IRGRP);
  3736.  
  3737.     if(FLAG_IS_SET(flags,FIBF_GRP_WRITE) && FLAG_IS_SET(flags,FIBF_GRP_DELETE))
  3738.         SET_FLAG(mode,S_IWGRP);
  3739.  
  3740.     if(FLAG_IS_SET(flags,FIBF_GRP_EXECUTE))
  3741.         SET_FLAG(mode,S_IXGRP);
  3742.  
  3743.  
  3744.     if(FLAG_IS_SET(flags,FIBF_OTR_READ))
  3745.         SET_FLAG(mode,S_IROTH);
  3746.  
  3747.     if(FLAG_IS_SET(flags,FIBF_OTR_WRITE) && FLAG_IS_SET(flags,FIBF_OTR_DELETE))
  3748.         SET_FLAG(mode,S_IWOTH);
  3749.  
  3750.     if(FLAG_IS_SET(flags,FIBF_OTR_EXECUTE))
  3751.         SET_FLAG(mode,S_IXOTH);
  3752.  
  3753.     time = fib->fib_Date.ds_Days * 24*60*60 +
  3754.            fib->fib_Date.ds_Minute * 60 +
  3755.           (fib->fib_Date.ds_Tick / TICKS_PER_SECOND);
  3756.  
  3757.     memset(st,0,sizeof(*st));
  3758.  
  3759.     st->st_dev        = (u_long)port;
  3760.     st->st_ino        = fib->fib_DiskKey;
  3761.     st->st_mode        = mode;
  3762.     st->st_mtime    = UNIX_TIME_OFFSET + time + 60*MinutesWest;    /* translate from local time to UTC */
  3763.     st->st_atime    = st->st_mtime;
  3764.     st->st_ctime    = st->st_mtime;
  3765.     st->st_uid        = fib->fib_OwnerUID;
  3766.     st->st_gid        = fib->fib_OwnerGID;
  3767.  
  3768.     if(FIB_IS_FILE(fib))
  3769.     {
  3770.         st->st_nlink = 1;
  3771.         st->st_size  = fib->fib_Size;
  3772.     }
  3773.     else
  3774.     {
  3775.         st->st_nlink = 2;
  3776.     }
  3777. }
  3778.  
  3779. int
  3780. amiga_stat(char *name, struct stat *st)
  3781. {
  3782.     char localName[MAX_FILENAME_LEN];
  3783.     struct MangleInfo mi;
  3784.     int result = ERROR;
  3785.  
  3786.     chkabort();
  3787.  
  3788.     ASSERT(name != NULL && st != NULL);
  3789.  
  3790.     ENTER();
  3791.     SHOWSTRING(name);
  3792.     SHOWVALUE(st);
  3793.  
  3794.     if(TranslateRelativePath(&name,localName,sizeof(localName)) == OK)
  3795.     {
  3796.         char * originalName = name;
  3797.  
  3798.         if(MangleName(&name,&mi) == OK)
  3799.         {
  3800.             int len;
  3801.  
  3802.             SHOWSTRING(name);
  3803.             SHOWSTRING(originalName);
  3804.  
  3805.             len = strlen(name);
  3806.             if((strcmp(originalName,"/") == SAME) || (len > 1 && name[len-2] == ':' && name[len-1] == '/'))
  3807.             {
  3808.                 struct timeval now;
  3809.  
  3810.                 SHOWMSG("this is the virtual root directory");
  3811.  
  3812.                 /* This must be our virtual root directory.
  3813.                  * Make something up.
  3814.                  */
  3815.                 memset(st,0,sizeof(*st));
  3816.                 GetSysTime((APTR)&now);
  3817.  
  3818.                 /* Nobody may write to this "directory". */
  3819.                 st->st_dev        = (u_long)"Virtual Root Directory";
  3820.                 st->st_ino        = 1;
  3821.                 st->st_mode        = S_IFDIR|S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
  3822.                 st->st_nlink    = 2;
  3823.                 st->st_mtime    = UNIX_TIME_OFFSET + now.tv_secs + 60*MinutesWest;    /* translate from local time to UTC */
  3824.                 st->st_atime    = st->st_mtime;
  3825.                 st->st_ctime    = st->st_mtime;
  3826.  
  3827.                 result = OK;
  3828.             }
  3829.             else
  3830.             {
  3831.                 BPTR fileLock;
  3832.  
  3833.                 SHOWMSG("this is a drawer or a file");
  3834.  
  3835.                 ForbidDOS();
  3836.  
  3837.                 fileLock = Lock((STRPTR)name,SHARED_LOCK);
  3838.                 if(fileLock != ZERO)
  3839.                 {
  3840.                     D_S(struct FileInfoBlock,fib);
  3841.  
  3842.                     if(Examine(fileLock,fib))
  3843.                     {
  3844.                         BPTR parentDir;
  3845.  
  3846.                         /* Check if this is the root directory. */
  3847.                         parentDir = ParentDir(fileLock);
  3848.                         if(parentDir != ZERO)
  3849.                         {
  3850.                             /* This is not the root directory. */
  3851.                             UnLock(parentDir);
  3852.                         }
  3853.                         else
  3854.                         {
  3855.                             /* So this is the root directory. Make sure
  3856.                              * that we return proper protection bits for
  3857.                              * it, i.e. that the directory is always
  3858.                              * readable, writable, etc. This may be
  3859.                              * necessary since on the Amiga, root
  3860.                              * directories cannot have any protection
  3861.                              * bits set. Note that the "deletable"
  3862.                              * bits don't make much sense, but then
  3863.                              * these bits work together with the
  3864.                              * writable bits. The lowest four bits
  3865.                              * remain zero, which enables them all.
  3866.                              */
  3867.                             fib->fib_Protection = FIBF_OTR_READ |
  3868.                                                   FIBF_OTR_WRITE |
  3869.                                                   FIBF_OTR_EXECUTE |
  3870.                                                   FIBF_OTR_DELETE |
  3871.                                                   FIBF_GRP_READ |
  3872.                                                   FIBF_GRP_WRITE |
  3873.                                                   FIBF_GRP_EXECUTE |
  3874.                                                   FIBF_GRP_DELETE;
  3875.                         }
  3876.  
  3877.                         ConvertFileInfoToStat(((struct FileLock *)BADDR(fileLock))->fl_Task,fib,st);
  3878.  
  3879.                         result = OK;
  3880.                     }
  3881.                     else
  3882.                     {
  3883.                         MapIoErrToErrno();
  3884.                     }
  3885.  
  3886.                     UnLock(fileLock);
  3887.                 }
  3888.                 else
  3889.                 {
  3890.                     LONG error = IoErr();
  3891.  
  3892.                     if(error == ERROR_OBJECT_IN_USE)
  3893.                     {
  3894.                         char parentName[MAX_FILENAME_LEN];
  3895.                         BPTR parentLock;
  3896.  
  3897.                         strcpy(parentName,name);
  3898.                         (*PathPart(parentName) = '\0');
  3899.  
  3900.                         parentLock = Lock(parentName,SHARED_LOCK);
  3901.                         if(parentLock != ZERO)
  3902.                         {
  3903.                             D_S(struct FileInfoBlock,fib);
  3904.  
  3905.                             if(Examine(parentLock,fib))
  3906.                             {
  3907.                                 STRPTR onlyFileName = FilePart(name);
  3908.  
  3909.                                 while(ExNext(parentLock,fib))
  3910.                                 {
  3911.                                     if(Stricmp(fib->fib_FileName,onlyFileName) == SAME)
  3912.                                     {
  3913.                                         ConvertFileInfoToStat(((struct FileLock *)BADDR(parentLock))->fl_Task,fib,st);
  3914.  
  3915.                                         result = OK;
  3916.                                         error = OK;
  3917.                                         break;
  3918.                                     }
  3919.                                 }
  3920.                             }
  3921.  
  3922.                             UnLock(parentLock);
  3923.                         }
  3924.                     }
  3925.  
  3926.                     if(error != OK)
  3927.                     {
  3928.                         SetIoErr(error);
  3929.  
  3930.                         MapIoErrToErrno();
  3931.                     }
  3932.                 }
  3933.  
  3934.                 PermitDOS();
  3935.             }
  3936.  
  3937.             if(result == OK)
  3938.             {
  3939.                 SHOWVALUE(st->st_dev);
  3940.                 SHOWVALUE(st->st_ino);
  3941.                 SHOWVALUE(st->st_size);
  3942.                 SHOWVALUE(st->st_nlink);
  3943.                 SHOWVALUE(st->st_mode);
  3944.                 SHOWVALUE(st->st_mtime);
  3945.                 SHOWVALUE(st->st_atime);
  3946.                 SHOWVALUE(st->st_ctime);
  3947.                 SHOWVALUE(st->st_uid);
  3948.                 SHOWVALUE(st->st_gid);
  3949.             }
  3950.             else
  3951.             {
  3952.                 SHOWVALUE(errno);
  3953.             }
  3954.  
  3955.             UnmangleName(&name,&mi);
  3956.         }
  3957.     }
  3958.  
  3959.     RETURN(result);
  3960.     return(result);
  3961. }
  3962.  
  3963. int
  3964. amiga_lstat(char *name, struct stat *statstruct)
  3965. {
  3966.     int result;
  3967.  
  3968.     chkabort();
  3969.  
  3970.     ENTER();
  3971.     SHOWSTRING(name);
  3972.     SHOWVALUE(statstruct);
  3973.  
  3974.     result = amiga_stat(name,statstruct);
  3975.  
  3976.     RETURN(result);
  3977.     return(result);
  3978. }
  3979.  
  3980. int
  3981. amiga_fstat(int fd,struct stat * st)
  3982. {
  3983.     struct UFB * ufb;
  3984.     int result = ERROR;
  3985.  
  3986.     chkabort();
  3987.  
  3988.     ASSERT(st != NULL);
  3989.  
  3990.     ENTER();
  3991.     SHOWVALUE(fd);
  3992.     SHOWVALUE(st);
  3993.  
  3994.     ufb = chkufb(fd);
  3995.     if(ufb != NULL)
  3996.     {
  3997.         if(FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  3998.         {
  3999.             long value;
  4000.             long size = sizeof(value);
  4001.  
  4002.             memset(st,0,sizeof(*st));
  4003.  
  4004.             st->st_dev    = (u_long)SocketBase;
  4005.             st->st_mode    = S_IFSOCK | S_IRUSR | S_IWUSR;
  4006.             st->st_uid    = geteuid();
  4007.             st->st_gid    = getegid();
  4008.  
  4009.             if(getsockopt(fd,SOL_SOCKET,SO_SNDBUF,&value,&size) == 0)
  4010.                 st->st_blksize = value;
  4011.  
  4012.             result = OK;
  4013.         }
  4014.         else
  4015.         {
  4016.             struct FileHandle * fileHandle = BADDR(ufb->ufbfh);
  4017.  
  4018.             /* Make sure that this stream doesn't
  4019.              * really refer to "NIL:".
  4020.              */
  4021.             if(fileHandle->fh_Type != NULL)
  4022.             {
  4023.                 D_S(struct FileInfoBlock,fib);
  4024.  
  4025.                 ForbidDOS();
  4026.  
  4027.                 if(ExamineFH(ufb->ufbfh,fib))
  4028.                 {
  4029.                     ConvertFileInfoToStat(fileHandle->fh_Type,fib,st);
  4030.  
  4031.                     result = OK;
  4032.                 }
  4033.                 else
  4034.                 {
  4035.                     MapIoErrToErrno();
  4036.                 }
  4037.  
  4038.                 PermitDOS();
  4039.             }
  4040.             else
  4041.             {
  4042.                 struct timeval tv;
  4043.  
  4044.                 /* Make up some phony data for a NIL: file handle. */
  4045.                 memset(st,0,sizeof(*st));
  4046.  
  4047.                 GetSysTime((APTR)&tv);
  4048.  
  4049.                 st->st_dev        = (u_long)0;
  4050.                 st->st_mode        = S_IFREG | S_IRUSR | S_IWUSR;
  4051.                 st->st_mtime    = UNIX_TIME_OFFSET + tv.tv_secs + 60*MinutesWest;    /* translate from local time to UTC */
  4052.                 st->st_atime    = st->st_mtime;
  4053.                 st->st_ctime    = st->st_mtime;
  4054.  
  4055.                 result = OK;
  4056.             }
  4057.         }
  4058.     }
  4059.     else
  4060.     {
  4061.         errno = EBADF;
  4062.     }
  4063.  
  4064.     RETURN(result);
  4065.     return(result);
  4066. }
  4067.  
  4068. /******************************************************************************/
  4069.  
  4070. int
  4071. amiga_chmod(char *name,int mode)
  4072. {
  4073.     struct MangleInfo mi;
  4074.     ULONG flags = 0;
  4075.     int result = ERROR;
  4076.  
  4077.     chkabort();
  4078.  
  4079.     ASSERT(name != NULL);
  4080.  
  4081.     ENTER();
  4082.     SHOWSTRING(name);
  4083.     SHOWVALUE(mode);
  4084.  
  4085.     /* Convert the file access modes into
  4086.      * Amiga typical protection bits.
  4087.      */
  4088.     if(FLAG_IS_SET(mode,S_IRUSR))
  4089.         SET_FLAG(flags,FIBF_READ);
  4090.  
  4091.     if(FLAG_IS_SET(mode,S_IWUSR))
  4092.     {
  4093.         SET_FLAG(flags,FIBF_WRITE);
  4094.         SET_FLAG(flags,FIBF_DELETE);
  4095.     }
  4096.  
  4097.     if(FLAG_IS_SET(mode,S_IXUSR))
  4098.         SET_FLAG(flags,FIBF_EXECUTE);
  4099.  
  4100.  
  4101.     if(FLAG_IS_SET(mode,S_IRGRP))
  4102.         SET_FLAG(flags,FIBF_GRP_READ);
  4103.  
  4104.     if(FLAG_IS_SET(mode,S_IWGRP))
  4105.     {
  4106.         SET_FLAG(flags,FIBF_GRP_WRITE);
  4107.         SET_FLAG(flags,FIBF_GRP_DELETE);
  4108.     }
  4109.  
  4110.     if(FLAG_IS_SET(mode,S_IXGRP))
  4111.         SET_FLAG(flags,FIBF_GRP_EXECUTE);
  4112.  
  4113.  
  4114.     if(FLAG_IS_SET(mode,S_IROTH))
  4115.         SET_FLAG(flags,FIBF_OTR_READ);
  4116.  
  4117.     if(FLAG_IS_SET(mode,S_IWOTH))
  4118.     {
  4119.         SET_FLAG(flags,FIBF_OTR_WRITE);
  4120.         SET_FLAG(flags,FIBF_OTR_DELETE);
  4121.     }
  4122.  
  4123.     if(FLAG_IS_SET(mode,S_IXOTH))
  4124.         SET_FLAG(flags,FIBF_OTR_EXECUTE);
  4125.  
  4126.     flags ^= (FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
  4127.  
  4128.     if(MangleName(&name,&mi) == OK)
  4129.     {
  4130.         ForbidDOS();
  4131.  
  4132.         if(SetProtection(name,flags))
  4133.         {
  4134.             result = OK;
  4135.         }
  4136.         else
  4137.         {
  4138.             LONG error = IoErr();
  4139.  
  4140.             /* Note sure about this one; is it really that important
  4141.              * that the file attribute change succeeds? This is a definite
  4142.              * FIXME.
  4143.              */
  4144.             if(error == ERROR_OBJECT_IN_USE)
  4145.             {
  4146.                 result = OK;
  4147.             }
  4148.             else
  4149.             {
  4150.                 SetIoErr(error);
  4151.  
  4152.                 MapIoErrToErrno();
  4153.             }
  4154.         }
  4155.  
  4156.         PermitDOS();
  4157.  
  4158.         UnmangleName(&name,&mi);
  4159.     }
  4160.  
  4161.     RETURN(result);
  4162.     return(result);
  4163. }
  4164.  
  4165. /******************************************************************************/
  4166.  
  4167. int
  4168. amiga_dup(int fd)
  4169. {
  4170.     struct UFB * ufb;
  4171.     int result = ERROR;
  4172.  
  4173.     chkabort();
  4174.  
  4175.     ENTER();
  4176.     SHOWVALUE(fd);
  4177.  
  4178.     ufb = chkufb(fd);
  4179.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  4180.     {
  4181.         fd = open("NIL:",O_RDWR,0777);
  4182.         if(fd != -1)
  4183.         {
  4184.             struct UFB * ufb2;
  4185.  
  4186.             ufb2 = chkufb(fd);
  4187.             if(ufb2 != NULL)
  4188.             {
  4189.                 if(SaveDescriptor(ufb2))
  4190.                 {
  4191.                     int sockfd;
  4192.  
  4193.                     sockfd = Dup2Socket(ufb->ufbfh,-1);
  4194.                     if(sockfd != -1)
  4195.                     {
  4196.                         SET_FLAG(ufb2->ufbflg,UFB_IS_SOCKET);
  4197.                         ufb2->ufbfh = sockfd;
  4198.  
  4199.                         result = fd;
  4200.                     }
  4201.                     else
  4202.                     {
  4203.                         close(fd);
  4204.                     }
  4205.                 }
  4206.                 else
  4207.                 {
  4208.                     close(fd);
  4209.                     errno = ENOMEM;
  4210.                 }
  4211.             }
  4212.             else
  4213.             {
  4214.                 close(fd);
  4215.                 errno = EBADF;
  4216.             }
  4217.         }
  4218.     }
  4219.     else
  4220.     {
  4221.         errno = ENOTSOCK;
  4222.     }
  4223.  
  4224.     RETURN(result);
  4225.     return(result);
  4226. }
  4227.  
  4228. /******************************************************************************/
  4229.  
  4230. int
  4231. amiga_dup2(int old_fd,int new_fd)
  4232. {
  4233.     struct UFB * old_ufb;
  4234.     struct UFB * new_ufb;
  4235.     int result = ERROR;
  4236.  
  4237.     chkabort();
  4238.  
  4239.     ENTER();
  4240.     SHOWVALUE(old_fd);
  4241.     SHOWVALUE(new_fd);
  4242.  
  4243.     old_ufb = chkufb(old_fd);
  4244.     new_ufb = chkufb(new_fd);
  4245.  
  4246.     if(old_ufb != NULL && FLAG_IS_SET(old_ufb->ufbflg,UFB_IS_SOCKET) && new_ufb != NULL)
  4247.     {
  4248.         int sockfd;
  4249.  
  4250.         if(FLAG_IS_SET(new_ufb->ufbflg,UFB_IS_SOCKET))
  4251.         {
  4252.             CloseSocket(new_ufb->ufbfh);
  4253.             sockfd = Dup2Socket(old_ufb->ufbfh,new_ufb->ufbfh);
  4254.         }
  4255.         else
  4256.         {
  4257.             if(SaveDescriptor(new_ufb))
  4258.             {
  4259.                 sockfd = Dup2Socket(old_ufb->ufbfh,-1);
  4260.             }
  4261.             else
  4262.             {
  4263.                 sockfd = -1;
  4264.                 errno = ENOMEM;
  4265.             }
  4266.         }
  4267.  
  4268.         if(sockfd != -1)
  4269.         {
  4270.             SET_FLAG(new_ufb->ufbflg,UFB_IS_SOCKET);
  4271.             new_ufb->ufbfh = sockfd;
  4272.  
  4273.             result = new_fd;
  4274.         }
  4275.     }
  4276.     else
  4277.     {
  4278.         errno = ENOTSOCK;
  4279.     }
  4280.  
  4281.     RETURN(result);
  4282.     return(result);
  4283. }
  4284.  
  4285. /******************************************************************************/
  4286.  
  4287. struct bcpl_name
  4288. {
  4289.     unsigned char name[MAX_BSTR_LEN];
  4290. };
  4291.  
  4292. int
  4293. amiga_chown(char *name,uid_t uid,gid_t gid)
  4294. {
  4295.     struct MangleInfo mi;
  4296.     int result = ERROR;
  4297.  
  4298.     chkabort();
  4299.  
  4300.     ASSERT(name != NULL);
  4301.  
  4302.     ENTER();
  4303.     SHOWSTRING(name);
  4304.     SHOWVALUE(uid);
  4305.     SHOWVALUE(gid);
  4306.  
  4307.     if(MangleName(&name,&mi) == OK)
  4308.     {
  4309.         /* AmigaDOS 3.0 and up have a SetOwner() call. */
  4310.         if(DOSBase->lib_Version >= 39)
  4311.         {
  4312.             if(SetOwner(name,(((LONG)uid) << 16) | gid))
  4313.                 result = OK;
  4314.             else
  4315.                 MapIoErrToErrno();
  4316.         }
  4317.         else
  4318.         {
  4319.             struct DevProc * dvp;
  4320.  
  4321.             /* For 2.04 and 2.1 we'll have to do this
  4322.              * manually...
  4323.              */
  4324.             dvp = GetDeviceProc(name,NULL);
  4325.             if(dvp != NULL)
  4326.             {
  4327.                 D_S(struct bcpl_name,newName);
  4328.                 int len;
  4329.  
  4330.                 len = strlen(name);
  4331.                 if(len > sizeof(newName->name)-1)
  4332.                     len = sizeof(newName->name)-1;
  4333.  
  4334.                 newName->name[0] = len;
  4335.                 strncpy(&newName->name[1],name,len);
  4336.  
  4337.                 /* This is almost identical in operation to ACTION_SET_PROTECTION. */
  4338.                 if(DoPkt(dvp->dvp_Port,ACTION_SET_OWNER,dvp->dvp_Lock,MKBADDR(newName),(((LONG)uid) << 16) | gid,0,0))
  4339.                     result = OK;
  4340.                 else
  4341.                     MapIoErrToErrno();
  4342.  
  4343.                 FreeDeviceProc(dvp);
  4344.             }
  4345.             else
  4346.             {
  4347.                 MapIoErrToErrno();
  4348.             }
  4349.         }
  4350.  
  4351.         UnmangleName(&name,&mi);
  4352.     }
  4353.  
  4354.     RETURN(result);
  4355.     return(result);
  4356. }
  4357.  
  4358. /******************************************************************************/
  4359.  
  4360. int
  4361. amiga_setegid(gid_t g)
  4362. {
  4363.     int result;
  4364.  
  4365.     chkabort();
  4366.  
  4367.     ENTER();
  4368.     SHOWVALUE(g);
  4369.  
  4370.     result = setregid(-1,g);
  4371.  
  4372.     RETURN(result);
  4373.     return(result);
  4374. }
  4375.  
  4376. /******************************************************************************/
  4377.  
  4378. int
  4379. amiga_seteuid(uid_t u)
  4380. {
  4381.     int result;
  4382.  
  4383.     chkabort();
  4384.  
  4385.     ENTER();
  4386.     SHOWVALUE(u);
  4387.     result = setreuid(-1,u);
  4388.  
  4389.     RETURN(result);
  4390.     return(result);
  4391. }
  4392.  
  4393. /******************************************************************************/
  4394.  
  4395. int
  4396. amiga_gettimeofday(struct timeval *tv)
  4397. {
  4398.     chkabort();
  4399.  
  4400.     ENTER();
  4401.     SHOWVALUE(tv);
  4402.  
  4403.     if(tv != NULL)
  4404.     {
  4405.         GetSysTime((APTR)tv);
  4406.         tv->tv_secs += UNIX_TIME_OFFSET + 60*MinutesWest;    /* translate from local time to UTC */
  4407.  
  4408.         SHOWVALUE(tv->tv_secs);
  4409.         SHOWVALUE(tv->tv_micro);
  4410.     }
  4411.  
  4412.     RETURN(0);
  4413.     return(0);
  4414. }
  4415.  
  4416. /******************************************************************************/
  4417.  
  4418. int
  4419. amiga_utime(char *name,struct utimbuf *time)
  4420. {
  4421.     struct MangleInfo mi;
  4422.     struct DateStamp ds;
  4423.     int result = ERROR;
  4424.  
  4425.     chkabort();
  4426.  
  4427.     ASSERT(name != NULL);
  4428.  
  4429.     ENTER();
  4430.     SHOWSTRING(name);
  4431.     SHOWVALUE(time);
  4432.  
  4433.     /* Use the current time? */
  4434.     if(time == NULL)
  4435.     {
  4436.         DateStamp(&ds);
  4437.     }
  4438.     else
  4439.     {
  4440.         ULONG seconds;
  4441.  
  4442.         /* Convert the time given. */
  4443.         if(time->modtime < (UNIX_TIME_OFFSET + 60*MinutesWest))
  4444.             seconds = 0;
  4445.         else
  4446.             seconds = time->modtime - (UNIX_TIME_OFFSET + 60*MinutesWest);    /* translate from UTC to local time */
  4447.  
  4448.         ds.ds_Days        = (seconds / (24*60*60));
  4449.         ds.ds_Minute    = (seconds % (24*60*60)) / 60;
  4450.         ds.ds_Tick        = (seconds               % 60) * TICKS_PER_SECOND;
  4451.     }
  4452.  
  4453.     if(MangleName(&name,&mi) == OK)
  4454.     {
  4455.         ForbidDOS();
  4456.  
  4457.         if(SetFileDate((STRPTR)name,&ds))
  4458.         {
  4459.             result = OK;
  4460.         }
  4461.         else
  4462.         {
  4463.             LONG error = IoErr();
  4464.  
  4465.             /* Note sure about this one; is it really that important
  4466.              * that the file date change succeeds? This is a definite
  4467.              * FIXME.
  4468.              */
  4469.             if(error == ERROR_OBJECT_IN_USE)
  4470.             {
  4471.                 result = OK;
  4472.             }
  4473.             else
  4474.             {
  4475.                 SetIoErr(error);
  4476.  
  4477.                 MapIoErrToErrno();
  4478.             }
  4479.         }
  4480.  
  4481.         PermitDOS();
  4482.  
  4483.         UnmangleName(&name,&mi);
  4484.     }
  4485.  
  4486.     RETURN(result);
  4487.     return(result);
  4488. }
  4489.  
  4490. /******************************************************************************/
  4491.  
  4492. VOID
  4493. amiga_sleep(unsigned int seconds)
  4494. {
  4495.     chkabort();
  4496.  
  4497.     ENTER();
  4498.     SHOWVALUE(seconds);
  4499.  
  4500.     if(seconds > 0)
  4501.     {
  4502.         ULONG timerSignal = (1UL << TimerPort->mp_SigBit);
  4503.         ULONG signalsReceived;
  4504.         ULONG signalsToWaitFor;
  4505.  
  4506.         TimerRequest->tr_node.io_Command    = TR_ADDREQUEST;
  4507.         TimerRequest->tr_time.tv_secs        = seconds;
  4508.         TimerRequest->tr_time.tv_micro        = 0;
  4509.  
  4510.         SetSignal(0,timerSignal);
  4511.         SendIO((struct IORequest *)TimerRequest);
  4512.  
  4513.         signalsToWaitFor = timerSignal;
  4514.         if(AllowBreak)
  4515.             signalsToWaitFor |= SIGBREAKF_CTRL_C;
  4516.  
  4517.         signalsReceived = Wait(signalsToWaitFor);
  4518.  
  4519.         /* Did we get a break signal while we were sleeping? */
  4520.         if(FLAG_IS_SET(signalsReceived,SIGBREAKF_CTRL_C))
  4521.         {
  4522.             if(CheckIO((struct IORequest *)TimerRequest) == BUSY)
  4523.                 AbortIO((struct IORequest *)TimerRequest);
  4524.  
  4525.             WaitIO((struct IORequest *)TimerRequest);
  4526.  
  4527.             /* And pull the brakes... */
  4528.             raise(SIGINT);
  4529.         }
  4530.  
  4531.         /* Proper termination. */
  4532.         if(FLAG_IS_SET(signalsReceived,timerSignal))
  4533.         {
  4534.             WaitIO((struct IORequest *)TimerRequest);
  4535.         }
  4536.     }
  4537.  
  4538.     LEAVE();
  4539. }
  4540.  
  4541. /******************************************************************************/
  4542.  
  4543. char *
  4544. amiga_crypt(char *key,char *salt)
  4545. {
  4546.     char *result;
  4547.  
  4548.     chkabort();
  4549.  
  4550.     ASSERT(key != NULL && salt != NULL);
  4551.  
  4552.     ENTER();
  4553.     SHOWSTRING(key);
  4554.     SHOWVALUE(salt);
  4555.     result = crypt(key,salt);
  4556.  
  4557.     RETURN(result);
  4558.     return(result);
  4559. }
  4560.  
  4561. /******************************************************************************/
  4562.  
  4563. char *
  4564. amiga_getpass(char *prompt)
  4565. {
  4566.     char *result;
  4567.  
  4568.     chkabort();
  4569.  
  4570.     ENTER();
  4571.     SHOWSTRING(prompt);
  4572.     result = getpass(prompt);
  4573.  
  4574.     RETURN(result);
  4575.     return(result);
  4576. }
  4577.  
  4578. /******************************************************************************/
  4579.  
  4580. int
  4581. amiga_setgid(gid_t id)
  4582. {
  4583.     int result;
  4584.  
  4585.     chkabort();
  4586.  
  4587.     ENTER();
  4588.     SHOWVALUE(id);
  4589.     result = setgid(id);
  4590.  
  4591.     RETURN(result);
  4592.     return(result);
  4593. }
  4594.  
  4595. /******************************************************************************/
  4596.  
  4597. int
  4598. amiga_setgroups(int ngroups,gid_t *groups)
  4599. {
  4600.     int result;
  4601.  
  4602.     chkabort();
  4603.  
  4604.     ASSERT(groups != NULL);
  4605.  
  4606.     ENTER();
  4607.     SHOWVALUE(ngroups);
  4608.     SHOWVALUE(groups);
  4609.  
  4610.     result = setgroups(ngroups,groups);
  4611.  
  4612.     RETURN(result);
  4613.     return(result);
  4614. }
  4615.  
  4616. /******************************************************************************/
  4617.  
  4618. gid_t
  4619. amiga_getgid(VOID)
  4620. {
  4621.     int result;
  4622.  
  4623.     chkabort();
  4624.  
  4625.     ENTER();
  4626.  
  4627.     if(RootMode)
  4628.         result = 0;
  4629.     else
  4630.         result = getgid();
  4631.  
  4632.     RETURN(result);
  4633.     return(result);
  4634. }
  4635.  
  4636. /******************************************************************************/
  4637.  
  4638. struct group *
  4639. amiga_getgrgid(gid_t gid)
  4640. {
  4641.     struct group *result;
  4642.  
  4643.     chkabort();
  4644.  
  4645.     ENTER();
  4646.     SHOWVALUE(gid);
  4647.  
  4648.     result = getgrgid(gid);
  4649.  
  4650.     RETURN(result);
  4651.     return(result);
  4652. }
  4653.  
  4654. /******************************************************************************/
  4655.  
  4656. struct group *
  4657. amiga_getgrnam(char * name)
  4658. {
  4659.     struct group *result;
  4660.  
  4661.     chkabort();
  4662.  
  4663.     ASSERT(name != NULL);
  4664.  
  4665.     ENTER();
  4666.     SHOWSTRING(name);
  4667.  
  4668.     result = getgrnam(name);
  4669.  
  4670.     RETURN(result);
  4671.     return(result);
  4672. }
  4673.  
  4674. /******************************************************************************/
  4675.  
  4676. int
  4677. amiga_getgroups(int ngroups, gid_t *groups)
  4678. {
  4679.     int result;
  4680.  
  4681.     chkabort();
  4682.  
  4683.     ASSERT(groups != NULL);
  4684.  
  4685.     ENTER();
  4686.     SHOWVALUE(ngroups);
  4687.     SHOWVALUE(groups);
  4688.  
  4689.     result = getgroups(ngroups,groups);
  4690.  
  4691.     RETURN(result);
  4692.     return(result);
  4693. }
  4694.  
  4695. /******************************************************************************/
  4696.  
  4697. struct hostent *
  4698. amiga_gethostbyaddr(char *addr, int len, int type)
  4699. {
  4700.     struct hostent *result;
  4701.  
  4702.     chkabort();
  4703.  
  4704.     ASSERT(addr != NULL);
  4705.  
  4706.     ENTER();
  4707.     SHOWVALUE(addr);
  4708.     SHOWVALUE(len);
  4709.     SHOWVALUE(type);
  4710.  
  4711.     result = gethostbyaddr(addr,len,type);
  4712.  
  4713.     RETURN(result);
  4714.     return(result);
  4715. }
  4716.  
  4717. /******************************************************************************/
  4718.  
  4719. struct hostent *
  4720. amiga_gethostbyname(char *name)
  4721. {
  4722.     struct hostent *result;
  4723.  
  4724.     chkabort();
  4725.  
  4726.     ASSERT(name != NULL);
  4727.  
  4728.     ENTER();
  4729.     SHOWSTRING(name);
  4730.  
  4731.     result = gethostbyname(name);
  4732.  
  4733.     RETURN(result);
  4734.     return(result);
  4735. }
  4736.  
  4737. /******************************************************************************/
  4738.  
  4739. struct netent *
  4740. amiga_getnetbyname(char *name)
  4741. {
  4742.     struct netent *result;
  4743.  
  4744.     chkabort();
  4745.  
  4746.     ASSERT(name != NULL);
  4747.  
  4748.     ENTER();
  4749.     SHOWSTRING(name);
  4750.  
  4751.     result = getnetbyname(name);
  4752.  
  4753.     RETURN(result);
  4754.     return(result);
  4755. }
  4756.  
  4757. /******************************************************************************/
  4758.  
  4759. int
  4760. amiga_gethostname(char *hostname,int size)
  4761. {
  4762.     int result;
  4763.  
  4764.     chkabort();
  4765.  
  4766.     ASSERT(hostname != NULL);
  4767.  
  4768.     ENTER();
  4769.     SHOWVALUE(hostname);
  4770.     SHOWVALUE(size);
  4771.  
  4772.     result = gethostname(hostname,size);
  4773.  
  4774.     if(result == 0)
  4775.         SHOWSTRING(hostname);
  4776.  
  4777.     RETURN(result);
  4778.     return(result);
  4779. }
  4780.  
  4781. /******************************************************************************/
  4782.  
  4783. struct passwd *
  4784. amiga_getpwnam(char *name)
  4785. {
  4786.     struct passwd *result;
  4787.  
  4788.     chkabort();
  4789.  
  4790.     ASSERT(name != NULL);
  4791.  
  4792.     ENTER();
  4793.     SHOWSTRING(name);
  4794.  
  4795.     result = getpwnam(name);
  4796.  
  4797.     RETURN(result);
  4798.     return(result);
  4799. }
  4800.  
  4801. /******************************************************************************/
  4802.  
  4803. struct passwd *
  4804. amiga_getpwuid(uid_t uid)
  4805. {
  4806.     struct passwd *result;
  4807.  
  4808.     chkabort();
  4809.  
  4810.     ENTER();
  4811.     SHOWVALUE(uid);
  4812.  
  4813.     result = getpwuid(uid);
  4814.  
  4815.     RETURN(result);
  4816.     return(result);
  4817. }
  4818.  
  4819. /******************************************************************************/
  4820.  
  4821. uid_t
  4822. amiga_getuid(VOID)
  4823. {
  4824.     uid_t result;
  4825.  
  4826.     chkabort();
  4827.  
  4828.     ENTER();
  4829.  
  4830.     if(RootMode)
  4831.         result = 0;
  4832.     else
  4833.         result = getuid();
  4834.  
  4835.     RETURN(result);
  4836.     return(result);
  4837. }
  4838.  
  4839. /******************************************************************************/
  4840.  
  4841. gid_t
  4842. amiga_getegid(VOID)
  4843. {
  4844.     gid_t result;
  4845.  
  4846.     chkabort();
  4847.  
  4848.     ENTER();
  4849.     result = getegid();
  4850.  
  4851.     RETURN(result);
  4852.     return(result);
  4853. }
  4854.  
  4855. /******************************************************************************/
  4856.  
  4857. uid_t
  4858. amiga_geteuid(VOID)
  4859. {
  4860.     uid_t result;
  4861.  
  4862.     chkabort();
  4863.  
  4864.     ENTER();
  4865.     result = geteuid();
  4866.  
  4867.     RETURN(result);
  4868.     return(result);
  4869. }
  4870.  
  4871. /******************************************************************************/
  4872.  
  4873. int
  4874. amiga_initgroups(char *name, gid_t basegroup)
  4875. {
  4876.     int result;
  4877.  
  4878.     chkabort();
  4879.  
  4880.     ASSERT(name != NULL);
  4881.  
  4882.     ENTER();
  4883.     SHOWSTRING(name);
  4884.     SHOWVALUE(basegroup);
  4885.  
  4886.     result = initgroups(name,basegroup);
  4887.  
  4888.     RETURN(result);
  4889.     return(result);
  4890. }
  4891.  
  4892. /******************************************************************************/
  4893.  
  4894. int
  4895. amiga_setuid(uid_t id)
  4896. {
  4897.     int result;
  4898.  
  4899.     chkabort();
  4900.  
  4901.     ENTER();
  4902.     SHOWVALUE(id);
  4903.  
  4904.     result = setuid(id);
  4905.  
  4906.     RETURN(result);
  4907.     return(result);
  4908. }
  4909.  
  4910. /******************************************************************************/
  4911.  
  4912. int
  4913. amiga_umask(int mask)
  4914. {
  4915.     int result;
  4916.  
  4917.     chkabort();
  4918.  
  4919.     ENTER();
  4920.     SHOWVALUE(mask);
  4921.  
  4922.     result = umask(mask);
  4923.  
  4924.     RETURN(result);
  4925.     return(result);
  4926. }
  4927.  
  4928. /******************************************************************************/
  4929.  
  4930. unsigned long
  4931. amiga_inet_addr(char *addr)
  4932. {
  4933.     unsigned long result;
  4934.  
  4935.     chkabort();
  4936.  
  4937.     ASSERT(addr != NULL);
  4938.  
  4939.     ENTER();
  4940.     SHOWSTRING(addr);
  4941.  
  4942.     result = inet_addr(addr);
  4943.  
  4944.     RETURN(result);
  4945.     return(result);
  4946. }
  4947.  
  4948. /******************************************************************************/
  4949.  
  4950. char *
  4951. amiga_inet_ntoa(struct in_addr in)
  4952. {
  4953.     char *result;
  4954.  
  4955.     chkabort();
  4956.  
  4957.     ENTER();
  4958.     SHOWVALUE(in.s_addr);
  4959.  
  4960.     result = Inet_NtoA(in.s_addr);
  4961.     SHOWSTRING(result);
  4962.  
  4963.     RETURN(result);
  4964.     return(result);
  4965. }
  4966.  
  4967. /******************************************************************************/
  4968.  
  4969. int    opterr = 1;
  4970. int    optind = 1;
  4971. int    optopt;
  4972. char * optarg;
  4973.  
  4974. int
  4975. amiga_getopt(int argc, char * argv[], char *opts)
  4976. {
  4977.     STATIC int sp = 1;
  4978.     int c;
  4979.     char *cp;
  4980.  
  4981.     ASSERT(argc > 0 && argv != NULL && opts != NULL);
  4982.  
  4983.     if(sp == 1)
  4984.     {
  4985.         if(optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
  4986.         {
  4987.             return(EOF);
  4988.         }
  4989.         else if(strcmp(argv[optind], "--") == NULL)
  4990.         {
  4991.             optind++;
  4992.             return(EOF);
  4993.         }
  4994.     }
  4995.  
  4996.     optopt = c = argv[optind][sp];
  4997.     if(c == ':' || (cp=index(opts, c)) == NULL)
  4998.     {
  4999.         if(opterr)
  5000.             fprintf(stderr, "%s%s%c\n", argv[0], ": illegal option -- ", c);
  5001.  
  5002.         if(argv[optind][++sp] == '\0')
  5003.         {
  5004.             optind++;
  5005.             sp = 1;
  5006.         }
  5007.  
  5008.         return('?');
  5009.     }
  5010.  
  5011.     if(*++cp == ':')
  5012.     {
  5013.         if(argv[optind][sp+1] != '\0')
  5014.         {
  5015.             optarg = &argv[optind++][sp+1];
  5016.         }
  5017.         else if(++optind >= argc)
  5018.         {
  5019.             if(opterr)
  5020.                 fprintf(stderr, "%s%s%c\n", argv[0], ": option requires an argument -- ", c);
  5021.  
  5022.             sp = 1;
  5023.             return('?');
  5024.         }
  5025.         else
  5026.         {
  5027.             optarg = argv[optind++];
  5028.         }
  5029.  
  5030.         sp = 1;
  5031.     }
  5032.     else
  5033.     {
  5034.         if(argv[optind][++sp] == '\0')
  5035.         {
  5036.             sp = 1;
  5037.             optind++;
  5038.         }
  5039.  
  5040.         optarg = NULL;
  5041.     }
  5042.  
  5043.     return(c);
  5044. }
  5045.  
  5046. /******************************************************************************/
  5047.  
  5048. /* This comes from util/lib.c */
  5049. STATIC BOOL
  5050. do_match(STRPTR str, STRPTR regexp)
  5051. {
  5052.     STRPTR p;
  5053.  
  5054.     for(p = regexp; (*p) != '\0' && (*str) != '\0' ; NULL)
  5055.     {
  5056.         switch(*p)
  5057.         {
  5058.             case '?':
  5059.  
  5060.                 str++;
  5061.                 p++;
  5062.  
  5063.                 break;
  5064.  
  5065.             /* Look for a character matching the one after the '*' */
  5066.             case '*':
  5067.  
  5068.                 p++;
  5069.  
  5070.                 if((*p) == '\0')
  5071.                     return(TRUE); /* Automatic match */
  5072.  
  5073.                 while((*str) != '\0')
  5074.                 {
  5075.                     while((*str) != '\0' && ToUpper(*p) != ToUpper(*str))
  5076.                         str++;
  5077.  
  5078.                     if(do_match(str,p))
  5079.                         return(TRUE);
  5080.  
  5081.                     if((*str) == '\0')
  5082.                         return(FALSE);
  5083.                     else
  5084.                         str++;
  5085.                 }
  5086.  
  5087.                 return(FALSE);
  5088.  
  5089.             default:
  5090.  
  5091.                 if(ToUpper(*str++) != ToUpper(*p++))
  5092.                     return(FALSE);
  5093.  
  5094.                 break;
  5095.         }
  5096.     }
  5097.  
  5098.     if((*p) == '\0' && (*str) == '\0')
  5099.         return(TRUE);
  5100.  
  5101.     if((*p) == '\0' && str[0] == '.' && str[1] == '\0')
  5102.         return(TRUE);
  5103.  
  5104.     if((*str) == '\0' && (*p) == '?')
  5105.     {
  5106.         while((*p) == '?')
  5107.             p++;
  5108.  
  5109.         return((BOOL)((*p) == '\0'));
  5110.     }
  5111.  
  5112.     if((*str) == '\0' && ((*p) == '*' && p[1] == '\0'))
  5113.         return(TRUE);
  5114.  
  5115.     return(FALSE);
  5116. }
  5117.  
  5118. STATIC VOID
  5119. nstrcpy_blank(const size_t maxSize,char *to,const char *from)
  5120. {
  5121.     size_t len = 0;
  5122.  
  5123.     while((*from) != '\0' && (*from) != ' ' && len < maxSize-1)
  5124.     {
  5125.         (*to++) = (*from++);
  5126.         len++;
  5127.     }
  5128.  
  5129.     (*to) = '\0';
  5130. }
  5131.  
  5132. STATIC VOID
  5133. fill_volume_list(struct List * list)
  5134. {
  5135.     struct DosList * dol;
  5136.  
  5137.     dol = NextDosEntry(LockDosList(LDF_VOLUMES|LDF_READ),
  5138.                                    LDF_VOLUMES|LDF_READ);
  5139.     while(dol != NULL)
  5140.     {
  5141.         /* Does the volume refer to a medium that is right
  5142.          * now present in the drive?
  5143.          */
  5144.         if(dol->dol_Task != NULL)
  5145.         {
  5146.             STRPTR name = BADDR(dol->dol_Name);
  5147.             struct Node * node;
  5148.             int len;
  5149.  
  5150.             len = name[0];
  5151.  
  5152.             node = malloc(sizeof(*node) + len+1);
  5153.             if(node != NULL)
  5154.             {
  5155.                 /* Copy the name of the volume. */
  5156.                 node->ln_Name = (char *)(node + 1);
  5157.                 strncpy(node->ln_Name,&name[1],len);
  5158.                 node->ln_Name[len] = '\0';
  5159.  
  5160.                 AddTail(list,node);
  5161.             }
  5162.         }
  5163.  
  5164.         dol = NextDosEntry(dol,LDF_VOLUMES|LDF_READ);
  5165.     }
  5166.  
  5167.     UnLockDosList(LDF_VOLUMES|LDF_READ);
  5168.  
  5169.     /* Now that we have collected all device nodes, check
  5170.      * whether the volumes are usable.
  5171.      */
  5172.     if(NOT IsListEmpty(list))
  5173.     {
  5174.         char localName[MAX_BSTR_LEN+1];
  5175.         D_S(struct InfoData,id);
  5176.         struct MsgPort * task;
  5177.         struct Node * node;
  5178.         struct Node * next;
  5179.         int len;
  5180.  
  5181.         for(node = list->lh_Head ;
  5182.             node->ln_Succ != NULL ;
  5183.             node = next)
  5184.         {
  5185.             next = node->ln_Succ;
  5186.  
  5187.             len = strlen(node->ln_Name);
  5188.             strncpy(localName,node->ln_Name,len);
  5189.             localName[len++] = ':';
  5190.             localName[len] = '\0';
  5191.  
  5192.             task = DeviceProc(localName);
  5193.             if(task == NULL || CANNOT DoPkt(task,ACTION_DISK_INFO,MKBADDR(id),    0,0,0,0))
  5194.             {
  5195.                 Remove(node);
  5196.                 free(node);
  5197.             }
  5198.         }
  5199.     }
  5200. }
  5201.  
  5202. STATIC int
  5203. deep_scan_drawer(char * drawerName,char * whichPattern,FILE * out)
  5204. {
  5205.     char * originalDrawerName;
  5206.     struct MangleInfo mi;
  5207.     int result = ERROR;
  5208.  
  5209.     originalDrawerName = drawerName;
  5210.     if(MangleName(&drawerName,&mi) == OK)
  5211.     {
  5212.         BPTR dirLock;
  5213.  
  5214.         dirLock = Lock(drawerName,SHARED_LOCK);
  5215.         if(dirLock != ZERO)
  5216.         {
  5217.             D_S(struct FileInfoBlock,fib);
  5218.  
  5219.             if(Examine(dirLock,fib))
  5220.             {
  5221.                 struct AnchorPath * ap;
  5222.  
  5223.                 ap = malloc(sizeof(*ap) + MAX_FILENAME_LEN);
  5224.                 if(ap != NULL)
  5225.                 {
  5226.                     BOOL stopped = FALSE;
  5227.                     BPTR oldDir;
  5228.                     LONG error;
  5229.  
  5230.                     oldDir = CurrentDir(dirLock);
  5231.  
  5232.                     memset(ap,0,sizeof(*ap) + MAX_FILENAME_LEN);
  5233.  
  5234.                     ap->ap_Strlen        = MAX_FILENAME_LEN;
  5235.                     ap->ap_BreakBits    = SIGBREAKF_CTRL_C;
  5236.  
  5237.                     if((error = MatchFirst("",ap)) == OK)
  5238.                     {
  5239.                         BOOL check;
  5240.  
  5241.                         do
  5242.                         {
  5243.                             D(("checking |%s|",ap->ap_Buf));
  5244.  
  5245.                             check = TRUE;
  5246.  
  5247.                             if(FIB_IS_FILE(&ap->ap_Info))
  5248.                             {
  5249.                                 SHOWMSG("this is a file");
  5250.                             }
  5251.                             else
  5252.                             {
  5253.                                 SHOWMSG("this is a drawer");
  5254.  
  5255.                                 if(FLAG_IS_CLEAR(ap->ap_Flags,APF_DIDDIR))
  5256.                                 {
  5257.                                     SET_FLAG(ap->ap_Flags,APF_DODIR);
  5258.                                 }
  5259.                                 else
  5260.                                 {
  5261.                                     CLEAR_FLAG(ap->ap_Flags,APF_DIDDIR);
  5262.                                     check = FALSE;
  5263.                                 }
  5264.                             }
  5265.  
  5266.                             if(check)
  5267.                             {
  5268.                                 SHOWSTRING(ap->ap_Info.fib_FileName);
  5269.  
  5270.                                 if(do_match(ap->ap_Info.fib_FileName,whichPattern))
  5271.                                 {
  5272.                                     D(("Output |%s/%s|",originalDrawerName,ap->ap_Buf));
  5273.                                     if(fprintf(out,"%s/%s\n",originalDrawerName,ap->ap_Buf) < 0)
  5274.                                     {
  5275.                                         stopped = TRUE;
  5276.                                         break;
  5277.                                     }
  5278.                                 }
  5279.                                 else
  5280.                                 {
  5281.                                     SHOWMSG("but its name does not match");
  5282.                                 }
  5283.                             }
  5284.                         }
  5285.                         while((error = MatchNext(ap)) == OK);
  5286.                     }
  5287.  
  5288.                     MatchEnd(ap);
  5289.  
  5290.                     CurrentDir(oldDir);
  5291.  
  5292.                     if(NOT stopped)
  5293.                     {
  5294.                         if(error == ERROR_NO_MORE_ENTRIES)
  5295.                         {
  5296.                             result = OK;
  5297.                         }
  5298.                         else if(error == ERROR_BREAK)
  5299.                         {
  5300.                             /* Don't do anything; we are going
  5301.                              * to delete the file anyway.
  5302.                              */
  5303.                         }
  5304.                         else
  5305.                         {
  5306.                             SetIoErr(error);
  5307.                             MapIoErrToErrno();
  5308.                         }
  5309.                     }
  5310.  
  5311.                     free(ap);
  5312.                 }
  5313.                 else
  5314.                 {
  5315.                     errno = ENOMEM;
  5316.                 }
  5317.             }
  5318.             else
  5319.             {
  5320.                 MapIoErrToErrno();
  5321.             }
  5322.  
  5323.             UnLock(dirLock);
  5324.         }
  5325.         else
  5326.         {
  5327.             MapIoErrToErrno();
  5328.         }
  5329.  
  5330.         UnmangleName(&drawerName,&mi);
  5331.     }
  5332.  
  5333.     return(result);
  5334. }
  5335.  
  5336. int
  5337. amiga_system(char *cmd)
  5338. {
  5339.     char redirectionFileBuffer[MAX_FILENAME_LEN];
  5340.     char *redirectionFile = redirectionFileBuffer;
  5341.     struct MangleInfo mi;
  5342.     int result = ERROR;
  5343.     char *stop;
  5344.     char *options;
  5345.     char *cmdName;
  5346.     int cmdLen,i;
  5347.     int quoteCount;
  5348.  
  5349.     chkabort();
  5350.  
  5351.     ASSERT(cmd != NULL);
  5352.  
  5353.     ENTER();
  5354.     SHOWSTRING(cmd);
  5355.  
  5356.     /* Handle two special cases for the smb client program,
  5357.      * which for reasons unknown to me resorts to calling
  5358.      * the Unix "ls" and "find" programs to collect lists
  5359.      * of files.
  5360.      *
  5361.      * The commands to watch for take the following forms:
  5362.      *
  5363.      *    /bin/ls file_to_list > output_filename
  5364.      *    find directory_to_list -name "pattern_to_list" -print > output_filename
  5365.      */
  5366.     stop = cmd;
  5367.     while((*stop) != ' ' && (*stop) != '\0')
  5368.         stop++;
  5369.  
  5370.     /* This will point behind the command name,
  5371.      * to the beginning of the list of options,
  5372.      * if any.
  5373.      */
  5374.     options = stop;
  5375.     while((*options) == ' ')
  5376.         options++;
  5377.  
  5378.     /* Now go and isolate the command name. */
  5379.     cmdName = cmd;
  5380.     cmdLen = stop-cmd;
  5381.     for(i = cmdLen - 1 ; i >= 0 ; i--)
  5382.     {
  5383.         if(cmd[i] == '/' || cmd[i] == ':')
  5384.         {
  5385.             cmdName = &cmd[i+1];
  5386.  
  5387.             stop = cmdName;
  5388.             while((*stop) != ' ' && (*stop) != '\0')
  5389.                 stop++;
  5390.  
  5391.             cmdLen = stop-cmdName;
  5392.  
  5393.             break;
  5394.         }
  5395.     }
  5396.  
  5397.     /* We have isolated the command name, now
  5398.      * find the redirection file name.
  5399.      */
  5400.     quoteCount = 0;
  5401.     strcpy(redirectionFile,"");
  5402.     for(i = 0 ; i < strlen(cmd) ; i++)
  5403.     {
  5404.         if(cmd[i] == '\"')
  5405.             quoteCount = (1-quoteCount);
  5406.  
  5407.         if(cmd[i] == '>' && quoteCount == 0)
  5408.         {
  5409.             char * from;
  5410.  
  5411.             from = &cmd[i+1];
  5412.             while((*from) == ' ')
  5413.                 from++;
  5414.  
  5415.             /* Note that we rely upon the
  5416.              * redirection file name not to contain
  5417.              * quote or escape characters.
  5418.              */
  5419.             nstrcpy_blank(sizeof(redirectionFileBuffer),redirectionFile,from);
  5420.             break;
  5421.         }
  5422.     }
  5423.  
  5424.     /* Now check which command we got. */
  5425.     if(cmdLen == 2 && Strnicmp(cmdName,"ls",2) == SAME)
  5426.     {
  5427.         char localDirName[MAX_FILENAME_LEN];
  5428.         char * dirName;
  5429.  
  5430.         dirName = ".";
  5431.  
  5432.         if(TranslateRelativePath(&dirName,localDirName,sizeof(localDirName)) == OK)
  5433.         {
  5434.             char whichPatternBuffer[MAX_FILENAME_LEN];
  5435.             char *whichPattern = whichPatternBuffer;
  5436.             BOOL oldAllowBreak = AllowBreak;
  5437.  
  5438.             /* We don't want to be interrupted. */
  5439.             AllowBreak = FALSE;
  5440.  
  5441.             /* Now find the pattern to use. */
  5442.             nstrcpy_blank(sizeof(whichPatternBuffer),whichPattern,options);
  5443.  
  5444.             SHOWMSG("doing `ls'");
  5445.             SHOWSTRING(whichPattern);
  5446.             SHOWSTRING(redirectionFile);
  5447.  
  5448.             /* What happens next is that the contents of the
  5449.              * current directory are scanned. All names
  5450.              * that match the given pattern are stored in the
  5451.              * redirection file.
  5452.              */
  5453.  
  5454.             if(MangleName(&redirectionFile,&mi) == OK)
  5455.             {
  5456.                 FILE * out;
  5457.  
  5458.                 ForbidDOS();
  5459.  
  5460.                 out = fopen(redirectionFile,"wb");
  5461.                 if(out != NULL)
  5462.                 {
  5463.                     SHOWSTRING(localDirName);
  5464.  
  5465.                     if(strcmp(localDirName,"/") == SAME)
  5466.                     {
  5467.                         struct List list;
  5468.                         struct Node * node;
  5469.  
  5470.                         SHOWMSG("listing volumes");
  5471.  
  5472.                         NewList(&list);
  5473.                         fill_volume_list(&list);
  5474.  
  5475.                         while((node = RemHead(&list)) != NULL)
  5476.                         {
  5477.                             D(("checking '%s'",node->ln_Name));
  5478.  
  5479.                             if(do_match(node->ln_Name,whichPattern))
  5480.                             {
  5481.                                 SHOWMSG(">>> matches");
  5482.  
  5483.                                 if(fprintf(out,"%s\n",node->ln_Name) < 0)
  5484.                                     break;
  5485.                             }
  5486.                             else
  5487.                             {
  5488.                                 SHOWMSG(">>> does not match");
  5489.                             }
  5490.  
  5491.                             free(node);
  5492.                         }
  5493.  
  5494.                         while((node = RemHead(&list)) != NULL)
  5495.                             free(node);
  5496.                     }
  5497.                     else
  5498.                     {
  5499.                         BPTR dirLock;
  5500.  
  5501.                         SHOWMSG("listing drawers");
  5502.  
  5503.                         dirLock = Lock("",SHARED_LOCK);
  5504.                         if(dirLock != ZERO)
  5505.                         {
  5506.                             D_S(struct FileInfoBlock,fib);
  5507.  
  5508.                             if(Examine(dirLock,fib))
  5509.                             {
  5510.                                 BOOL stopped = FALSE;
  5511.  
  5512.                                 while(ExNext(dirLock,fib))
  5513.                                 {
  5514.                                     D(("checking '%s'",fib->fib_FileName));
  5515.  
  5516.                                     if(do_match(fib->fib_FileName,whichPattern))
  5517.                                     {
  5518.                                         SHOWMSG(">>> matches");
  5519.  
  5520.                                         if(fprintf(out,"%s\n",fib->fib_FileName) < 0)
  5521.                                         {
  5522.                                             stopped = TRUE;
  5523.                                             break;
  5524.                                         }
  5525.                                     }
  5526.                                     else
  5527.                                     {
  5528.                                         SHOWMSG(">>> does not match");
  5529.                                     }
  5530.                                 }
  5531.  
  5532.                                 if(NOT stopped)
  5533.                                 {
  5534.                                     LONG error = IoErr();
  5535.  
  5536.                                     if(error == ERROR_NO_MORE_ENTRIES)
  5537.                                     {
  5538.                                         result = OK;
  5539.                                     }
  5540.                                     else
  5541.                                     {
  5542.                                         SetIoErr(error);
  5543.                                         MapIoErrToErrno();
  5544.                                     }
  5545.                                 }
  5546.                             }
  5547.                             else
  5548.                             {
  5549.                                 MapIoErrToErrno();
  5550.                             }
  5551.  
  5552.                             UnLock(dirLock);
  5553.                         }
  5554.                         else
  5555.                         {
  5556.                             MapIoErrToErrno();
  5557.                         }
  5558.                     }
  5559.  
  5560.                     fclose(out);
  5561.  
  5562.                     if(result != OK)
  5563.                         DeleteFile(redirectionFile);
  5564.                 }
  5565.  
  5566.                 PermitDOS();
  5567.  
  5568.                 UnmangleName(&cmd,&mi);
  5569.             }
  5570.  
  5571.             AllowBreak = oldAllowBreak;
  5572.         }
  5573.     }
  5574.     else if (cmdLen == 4 && Strnicmp(cmdName,"find",4) == SAME)
  5575.     {
  5576.         char whichDrawerBuffer[MAX_FILENAME_LEN];
  5577.         char * whichDrawer = whichDrawerBuffer;
  5578.         char whichPattern[MAX_FILENAME_LEN];
  5579.         const int _nameLen = strlen("-name");
  5580.         BOOL oldAllowBreak = AllowBreak;
  5581.         struct Node * node;
  5582.  
  5583.         /* We don't want to be interrupted. */
  5584.         AllowBreak = FALSE;
  5585.  
  5586.         /* Now find the drawer to examine. */
  5587.         nstrcpy_blank(sizeof(whichDrawerBuffer),whichDrawer,options);
  5588.  
  5589.         /* Find the pattern to search for. */
  5590.         strcpy(whichPattern,"");
  5591.         for(i = 0 ; i < strlen(options) ; i++)
  5592.         {
  5593.             if(Strnicmp(&options[i],"-name",_nameLen) == SAME)
  5594.             {
  5595.                 const int maxLen = sizeof(whichPattern)-1;
  5596.                 int whichPatternLen;
  5597.                 int escapeCount;
  5598.                 int quoteCount;
  5599.                 char * from;
  5600.                 char * to;
  5601.  
  5602.                 /* `from' should now point straight at the
  5603.                  * search pattern, which is probably enclosed
  5604.                  * in quote characters.
  5605.                  */
  5606.                 from = &options[i+_nameLen];
  5607.                 while((*from) == ' ')
  5608.                     from++;
  5609.  
  5610.                 to = whichPattern;
  5611.                 whichPatternLen = 0;
  5612.                 quoteCount = 0;
  5613.                 escapeCount = 0;
  5614.                 while((*from) != '\0' && whichPatternLen < maxLen)
  5615.                 {
  5616.                     if(escapeCount != 0)
  5617.                     {
  5618.                         (*to++) = (*from++);
  5619.                         whichPatternLen++;
  5620.                         escapeCount = 0;
  5621.                     }
  5622.                     else if((*from) == '\\')
  5623.                     {
  5624.                         escapeCount = (1-escapeCount);
  5625.                         from++;
  5626.                     }
  5627.                     else if ((*from) == '\"')
  5628.                     {
  5629.                         quoteCount = (1-quoteCount);
  5630.                         from++;
  5631.                     }
  5632.                     else
  5633.                     {
  5634.                         if((*from) == ' ' && quoteCount == 0)
  5635.                         {
  5636.                             break;
  5637.                         }
  5638.                         else
  5639.                         {
  5640.                             (*to++) = (*from++);
  5641.                             whichPatternLen++;
  5642.                         }
  5643.                     }
  5644.                 }
  5645.  
  5646.                 (*to) = '\0';
  5647.             }
  5648.         }
  5649.  
  5650.         SHOWMSG("doing `find'");
  5651.         SHOWSTRING(whichDrawer);
  5652.         SHOWSTRING(whichPattern);
  5653.         SHOWSTRING(redirectionFile);
  5654.  
  5655.         /* Things are a little bit more complicated here. The
  5656.          * "find" program scans recursively through a directory
  5657.          * tree. We emulate this behaviour by having the MatchFirst/MatchNext
  5658.          * routines iterate through the directory tree. The
  5659.          * name of every file found is matched against the given
  5660.          * pattern and, if necessary, written to the redirection
  5661.          * file. Note that matching is performed only on the
  5662.          * file name, not on the entire path.
  5663.          */
  5664.  
  5665.         if(MangleName(&redirectionFile,&mi) == OK)
  5666.         {
  5667.             FILE * out;
  5668.  
  5669.             ForbidDOS();
  5670.  
  5671.             out = fopen(redirectionFile,"wb");
  5672.             if(out != NULL)
  5673.             {
  5674.                 char localDirName[MAX_FILENAME_LEN];
  5675.                 char * dirName;
  5676.  
  5677.                 dirName = whichDrawer;
  5678.  
  5679.                 if(TranslateRelativePath(&dirName,localDirName,sizeof(localDirName)) == OK)
  5680.                 {
  5681.                     D(("listing path '%s'",dirName));
  5682.  
  5683.                     if(strcmp(dirName,"/") == SAME)
  5684.                     {
  5685.                         struct List list;
  5686.  
  5687.                         SHOWMSG("checking all 'drawers' in the fake root");
  5688.  
  5689.                         NewList(&list);
  5690.                         fill_volume_list(&list);
  5691.  
  5692.                         while((node = RemHead(&list)) != NULL)
  5693.                         {
  5694.                             strcpy(localDirName,"/");
  5695.                             strcat(localDirName,node->ln_Name);
  5696.                             free(node);
  5697.  
  5698.                             D(("checking '%s'",localDirName));
  5699.  
  5700.                             result = deep_scan_drawer(localDirName,whichPattern,out);
  5701.                             if(result != OK)
  5702.                                 break;
  5703.                         }
  5704.  
  5705.                         while((node = RemHead(&list)) != NULL)
  5706.                             free(node);
  5707.                     }
  5708.                     else
  5709.                     {
  5710.                         SHOWMSG("checking only a local drawer");
  5711.  
  5712.                         result = deep_scan_drawer(dirName,whichPattern,out);
  5713.                     }
  5714.                 }
  5715.  
  5716.                 fclose(out);
  5717.  
  5718.                 if(result != OK)
  5719.                     DeleteFile(redirectionFile);
  5720.             }
  5721.  
  5722.             PermitDOS();
  5723.  
  5724.             UnmangleName(&cmd,&mi);
  5725.         }
  5726.  
  5727.         AllowBreak = oldAllowBreak;
  5728.     }
  5729.     else
  5730.     {
  5731.         if(MangleName(&cmd,&mi) == OK)
  5732.         {
  5733.             ForbidDOS();
  5734.             result = system(cmd);
  5735.             PermitDOS();
  5736.  
  5737.             UnmangleName(&cmd,&mi);
  5738.         }
  5739.     }
  5740.  
  5741.     RETURN(result);
  5742.     return(result);
  5743. }
  5744.  
  5745. /******************************************************************************/
  5746.  
  5747. int
  5748. amiga_fork(VOID)    /* dummy */
  5749. {
  5750.     int result;
  5751.  
  5752.     chkabort();
  5753.  
  5754.     ENTER();
  5755.  
  5756.     result = ERROR;
  5757.     errno = ENOSYS;
  5758.  
  5759.     RETURN(result);
  5760.     return(result);
  5761. }
  5762.  
  5763. /******************************************************************************/
  5764.  
  5765. STATIC BOOL
  5766. SetFileSocket(FILE *stream,int sockfd)
  5767. {
  5768.     struct UFB * ufb;
  5769.     BOOL success = FALSE;
  5770.  
  5771.     ASSERT(stream != NULL);
  5772.  
  5773.     ENTER();
  5774.  
  5775.     /* Check which buffer the file
  5776.      * is attached to.
  5777.      */
  5778.     ufb = chkufb(fileno(stream));
  5779.     if(ufb != NULL)
  5780.     {
  5781.         SHOWVALUE(ufb);
  5782.  
  5783.         /* Save the file handle. */
  5784.         if(SaveDescriptor(ufb))
  5785.         {
  5786.             /* And put the socket in its place. */
  5787.             ufb->ufbfh = sockfd;
  5788.             SET_FLAG(ufb->ufbflg,UFB_IS_SOCKET);
  5789.  
  5790.             success = TRUE;
  5791.         }
  5792.     }
  5793.     else
  5794.     {
  5795.         SHOWMSG("no ufb");
  5796.     }
  5797.  
  5798.     RETURN(success);
  5799.     return(success);
  5800. }
  5801.  
  5802. STATIC VOID
  5803. DaemonInit(VOID)
  5804. {
  5805.     struct DaemonMessage * dm;
  5806.     int sock;
  5807.  
  5808.     ENTER();
  5809.  
  5810.     /* This routine is called when the program starts up.
  5811.      * If it was launched by the INet super server, this
  5812.      * program will run as a daemon. We pick up its
  5813.      * socket input stream and attach it to our stdio
  5814.      * streams.
  5815.      */
  5816.     dm = (struct DaemonMessage *)((struct Process *)FindTask(NULL))->pr_ExitData;
  5817.     if(dm != NULL)
  5818.     {
  5819.         sock = ObtainSocket(dm->dm_ID,dm->dm_Family,dm->dm_Type,0);
  5820.         if(sock != -1)
  5821.         {
  5822.             BOOL success = FALSE;
  5823.             int sock_stdin;
  5824.             int sock_stdout;
  5825.             int sock_stderr;
  5826.  
  5827.             sock_stdin    = Dup2Socket(sock,-1);
  5828.             sock_stdout    = Dup2Socket(sock,-1);
  5829.             sock_stderr    = Dup2Socket(sock,-1);
  5830.  
  5831.             if(sock_stdin != -1 && sock_stdout != -1 && sock_stderr != -1)
  5832.             {
  5833.                 SHOWMSG("got all sockets");
  5834.  
  5835.                 D(("stdin  = sock %ld",sock_stdin));
  5836.                 D(("stdout = sock %ld",sock_stdout));
  5837.                 D(("stderr = sock %ld",sock_stderr));
  5838.  
  5839.                 if(SetFileSocket(stdin,sock_stdin) &&
  5840.                    SetFileSocket(stdout,sock_stdout) &&
  5841.                    SetFileSocket(stderr,sock_stderr))
  5842.                 {
  5843.                     SHOWMSG("and all streams are initialized");
  5844.  
  5845.                     success = TRUE;
  5846.                 }
  5847.                 else
  5848.                 {
  5849.                     SHOWMSG("failed to initialize streams");
  5850.                 }
  5851.             }
  5852.             else
  5853.             {
  5854.                 SHOWMSG("didn't get the sockets");
  5855.             }
  5856.  
  5857.             if(NO success)
  5858.             {
  5859.                 if(sock_stdin != -1)
  5860.                     CloseSocket(sock_stdin);
  5861.  
  5862.                 if(sock_stdout != -1)
  5863.                     CloseSocket(sock_stdout);
  5864.  
  5865.                 if(sock_stderr != -1)
  5866.                     CloseSocket(sock_stderr);
  5867.             }
  5868.         }
  5869.         else
  5870.         {
  5871.             SHOWMSG("no socket");
  5872.         }
  5873.     }
  5874.     else
  5875.     {
  5876.         SHOWMSG("No daemon message");
  5877.     }
  5878.  
  5879.     LEAVE();
  5880. }
  5881.  
  5882. /******************************************************************************/
  5883.  
  5884. VOID
  5885. __tzset(VOID)
  5886. {
  5887.     STATIC char TimeZoneName[20] = "";
  5888.  
  5889.     /* This routine sets up the internal
  5890.      * time zone variable according to
  5891.      * the local settings.
  5892.      */
  5893.     if(STRING_IS_EMPTY(TimeZoneName))
  5894.     {
  5895.         int hoursWest = MinutesWest / 60;
  5896.  
  5897.         if(hoursWest >= 0)
  5898.             sprintf(TimeZoneName,"GMT+%02d", hoursWest);
  5899.         else
  5900.             sprintf(TimeZoneName,"GMT-%02d",-hoursWest);
  5901.     }
  5902.  
  5903.     _TZ = TimeZoneName;
  5904. }
  5905.  
  5906. /******************************************************************************/
  5907.  
  5908. time_t
  5909. time(time_t *timeptr)
  5910. {
  5911.     time_t currentTime;
  5912.     struct timeval tv;
  5913.  
  5914.     chkabort();
  5915.  
  5916.     GetSysTime((APTR)&tv);
  5917.  
  5918.     currentTime = UNIX_TIME_OFFSET + tv.tv_secs + 60*MinutesWest;    /* translate from local time to UTC */
  5919.  
  5920.     if(timeptr != NULL)
  5921.         (*timeptr) = currentTime;
  5922.  
  5923.     return(currentTime);
  5924. }
  5925.  
  5926. /******************************************************************************/
  5927.  
  5928. STATIC struct tm *
  5929. ConvertTime(ULONG seconds)
  5930. {
  5931.     STATIC struct tm tm;
  5932.     struct ClockData clockData;
  5933.     ULONG delta;
  5934.  
  5935.     chkabort();
  5936.  
  5937.     Amiga2Date(seconds,&clockData);
  5938.  
  5939.     tm.tm_sec    = clockData.sec;
  5940.     tm.tm_min    = clockData.min;
  5941.     tm.tm_hour    = clockData.hour;
  5942.     tm.tm_mday    = clockData.mday;
  5943.     tm.tm_mon    = clockData.month - 1;
  5944.     tm.tm_year    = clockData.year - 1900;
  5945.     tm.tm_wday    = clockData.wday;
  5946.     tm.tm_isdst    = 0;
  5947.  
  5948.     clockData.mday    = 1;
  5949.     clockData.month    = 1;
  5950.  
  5951.     delta = Date2Amiga(&clockData);
  5952.  
  5953.     tm.tm_yday = (seconds - delta) / (24*60*60);
  5954.  
  5955.     return(&tm);
  5956. }
  5957.  
  5958. struct tm *
  5959. gmtime(const time_t *t)
  5960. {
  5961.     struct tm * result;
  5962.     ULONG seconds;
  5963.  
  5964.     if((*t) < UNIX_TIME_OFFSET)
  5965.         seconds = 0;
  5966.     else
  5967.         seconds = (*t) - UNIX_TIME_OFFSET;
  5968.  
  5969.     result = ConvertTime(seconds);
  5970.  
  5971.     return(result);
  5972. }
  5973.  
  5974. struct tm *
  5975. localtime(const time_t *t)
  5976. {
  5977.     struct tm * result;
  5978.     ULONG seconds;
  5979.  
  5980.     if((*t) < (UNIX_TIME_OFFSET + 60*MinutesWest))
  5981.         seconds = 0;
  5982.     else
  5983.         seconds = (*t) - (UNIX_TIME_OFFSET + 60*MinutesWest);    /* translate from UTC to local time */
  5984.  
  5985.     result = ConvertTime(seconds);
  5986.  
  5987.     return(result);
  5988. }
  5989.  
  5990. /******************************************************************************/
  5991.  
  5992. int
  5993. amiga_strcasecmp(char *a,char *b)
  5994. {
  5995.     int result;
  5996.  
  5997.     ASSERT(a != NULL && b != NULL);
  5998.  
  5999.     result = Stricmp((STRPTR)a,b);
  6000.  
  6001.     return(result);
  6002. }
  6003.  
  6004. int
  6005. amiga_strncasecmp(char *a,char *b,int len)
  6006. {
  6007.     int result;
  6008.  
  6009.     ASSERT(a != NULL && b != NULL);
  6010.  
  6011.     result = Strnicmp(a,b,len);
  6012.  
  6013.     return(result);
  6014. }
  6015.  
  6016. /******************************************************************************/
  6017.  
  6018. VOID
  6019. (*amiga_signal(int which,VOID (* action)(int)))(int)
  6020. {
  6021.     VOID (* result)(int);
  6022.  
  6023.     chkabort();
  6024.  
  6025.     ENTER();
  6026.  
  6027.     if(SIGABRT <= which && which <= SIGTERM)
  6028.         result = signal(which,action);
  6029.     else
  6030.         result = SIG_DFL;
  6031.  
  6032.     RETURN(result);
  6033.     return(result);
  6034. }
  6035.  
  6036. /******************************************************************************/
  6037.  
  6038. VOID
  6039. amiga_alarm(int seconds)    /* dummy */
  6040. {
  6041.     chkabort();
  6042.  
  6043.     ENTER();
  6044.  
  6045.     LEAVE();
  6046. }
  6047.  
  6048. /******************************************************************************/
  6049.  
  6050. int
  6051. amiga_waitpid(pid_t pid,int *status,int options)    /* dummy */
  6052. {
  6053.     int result;
  6054.  
  6055.     chkabort();
  6056.  
  6057.     ENTER();
  6058.  
  6059.     result = ERROR;
  6060.     errno = ENOSYS;
  6061.  
  6062.     RETURN(result);
  6063.     return(result);
  6064. }
  6065.  
  6066. /******************************************************************************/
  6067.  
  6068. long
  6069. amiga_setsid(VOID)
  6070. {
  6071.     long result;
  6072.  
  6073.     chkabort();
  6074.  
  6075.     ENTER();
  6076.  
  6077.     result = (long)setsid();
  6078.  
  6079.     RETURN(result);
  6080.     return(result);
  6081. }
  6082.  
  6083. /******************************************************************************/
  6084.  
  6085. int
  6086. amiga_setreuid(uid_t real, uid_t eff)
  6087. {
  6088.     int result;
  6089.  
  6090.     chkabort();
  6091.  
  6092.     ENTER();
  6093.  
  6094.     result = setreuid(real,eff);
  6095.  
  6096.     RETURN(result);
  6097.     return(result);
  6098. }
  6099.  
  6100. /******************************************************************************/
  6101.  
  6102. int
  6103. amiga_setregid(gid_t real, gid_t eff)
  6104. {
  6105.     int result;
  6106.  
  6107.     chkabort();
  6108.  
  6109.     ENTER();
  6110.  
  6111.     result = setregid(real,eff);
  6112.  
  6113.     RETURN(result);
  6114.     return(result);
  6115. }
  6116.  
  6117. /******************************************************************************/
  6118.  
  6119. int
  6120. amiga_getsockname(int sockfd,struct sockaddr *name,int *namelen)
  6121. {
  6122.     struct UFB * ufb;
  6123.     int result = ERROR;
  6124.  
  6125.     chkabort();
  6126.  
  6127.     ASSERT(name != NULL && namelen != NULL);
  6128.  
  6129.     ENTER();
  6130.  
  6131.     ufb = chkufb(sockfd);
  6132.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  6133.         result = getsockname(ufb->ufbfh,name,(LONG *)namelen);
  6134.     else
  6135.         errno = ENOTSOCK;
  6136.  
  6137.     RETURN(result);
  6138.     return(result);
  6139. }
  6140.  
  6141. /******************************************************************************/
  6142.  
  6143. int
  6144. amiga_statfs(char *name,struct statfs *f)
  6145. {
  6146.     char localName[MAX_FILENAME_LEN];
  6147.     int result = ERROR;
  6148.  
  6149.     chkabort();
  6150.  
  6151.     ASSERT(name != NULL && f != NULL);
  6152.  
  6153.     ENTER();
  6154.  
  6155.     SHOWSTRING(name);
  6156.     SHOWVALUE(f);
  6157.  
  6158.     if(TranslateRelativePath(&name,localName,sizeof(localName)) == OK)
  6159.     {
  6160.         /* Make up something for the virtual root directory. */
  6161.         if(strcmp(name,"/") == SAME)
  6162.         {
  6163.             memset(f,0,sizeof(*f));
  6164.  
  6165.             f->f_fsize = 512;
  6166.  
  6167.             /* Try to reuse the data from our last scan. */
  6168.             if(RootBlocks > 0 && RootBlocksUsed > 0)
  6169.             {
  6170.                 f->f_blocks    = RootBlocks;
  6171.                 f->f_bfree    = RootBlocks - RootBlocksUsed;
  6172.             }
  6173.             else
  6174.             {
  6175.                 f->f_blocks    = 0x7FFFFFFF/f->f_fsize;
  6176.                 f->f_bfree    = f->f_blocks - 1;
  6177.             }
  6178.  
  6179.             f->f_bsize    = f->f_fsize;
  6180.             f->f_bavail    = f->f_bfree;
  6181.  
  6182.             SHOWVALUE(f->f_fsize);
  6183.             SHOWVALUE(f->f_bsize);
  6184.             SHOWVALUE(f->f_blocks);
  6185.             SHOWVALUE(f->f_bfree);
  6186.             SHOWVALUE(f->f_bavail);
  6187.  
  6188.             result = OK;
  6189.         }
  6190.         else
  6191.         {
  6192.             struct MangleInfo mi;
  6193.             BPTR fileLock;
  6194.  
  6195.             if(MangleName(&name,&mi) == OK)
  6196.             {
  6197.                 ForbidDOS();
  6198.  
  6199.                 fileLock = Lock(name,SHARED_LOCK);
  6200.                 if(fileLock != ZERO)
  6201.                 {
  6202.                     D_S(struct InfoData,id);
  6203.  
  6204.                     if(Info(fileLock,id))
  6205.                     {
  6206.                         memset(f,0,sizeof(*f));
  6207.  
  6208.                         /* Make sure that these never drop to zero. */
  6209.                         if(id->id_NumBlocks == 0)
  6210.                             id->id_NumBlocks = 1;
  6211.  
  6212.                         if(id->id_BytesPerBlock == 0)
  6213.                             id->id_BytesPerBlock = 512;
  6214.  
  6215.                         f->f_fsize    = id->id_BytesPerBlock;                        /* fundamental file system block size */
  6216.                         f->f_blocks    = id->id_NumBlocks;                            /* total data blocks in file system */
  6217.                         f->f_bfree    = id->id_NumBlocks - id->id_NumBlocksUsed;    /* free blocks in fs */
  6218.                         f->f_bsize    = f->f_fsize;                                /* optimal transfer block size */
  6219.                         f->f_bavail    = f->f_bfree;                                /* free blocks avail to non-superuser */
  6220.  
  6221.                         SHOWVALUE(f->f_fsize);
  6222.                         SHOWVALUE(f->f_bsize);
  6223.                         SHOWVALUE(f->f_blocks);
  6224.                         SHOWVALUE(f->f_bfree);
  6225.                         SHOWVALUE(f->f_bavail);
  6226.  
  6227.                         result = OK;
  6228.                     }
  6229.                     else
  6230.                     {
  6231.                         MapIoErrToErrno();
  6232.                     }
  6233.  
  6234.                     UnLock(fileLock);
  6235.                 }
  6236.                 else
  6237.                 {
  6238.                     MapIoErrToErrno();
  6239.                 }
  6240.  
  6241.                 PermitDOS();
  6242.  
  6243.                 UnmangleName(&name,&mi);
  6244.             }
  6245.         }
  6246.     }
  6247.  
  6248.     RETURN(result);
  6249.     return(result);
  6250. }
  6251.  
  6252. /******************************************************************************/
  6253.  
  6254. int
  6255. amiga_execl(char *path,char *arg,...)    /* dummy */
  6256. {
  6257.     int result;
  6258.  
  6259.     chkabort();
  6260.  
  6261.     ENTER();
  6262.  
  6263.     result = ERROR;
  6264.     errno = ENOSYS;
  6265.  
  6266.     RETURN(result);
  6267.     return(result);
  6268. }
  6269.  
  6270. /******************************************************************************/
  6271.  
  6272. char *
  6273. amiga_strerror(int error)
  6274. {
  6275.     struct TagItem tags[2];
  6276.     char *result;
  6277.  
  6278.     chkabort();
  6279.  
  6280.     ENTER();
  6281.  
  6282.     tags[0].ti_Tag    = SBTM_GETVAL(SBTC_ERRNOSTRPTR);
  6283.     tags[0].ti_Data    = error;
  6284.     tags[1].ti_Tag    = TAG_END;
  6285.  
  6286.     SocketBaseTagList(tags);
  6287.  
  6288.     result = (char *)tags[0].ti_Data;
  6289.  
  6290.     RETURN(result);
  6291.     return(result);
  6292. }
  6293.  
  6294. /******************************************************************************/
  6295.  
  6296. int
  6297. amiga_access(char *name,int modes)
  6298. {
  6299.     struct MangleInfo mi;
  6300.     int result = ERROR;
  6301.  
  6302.     chkabort();
  6303.  
  6304.     ASSERT(name != NULL);
  6305.  
  6306.     ENTER();
  6307.  
  6308.     if(MangleName(&name,&mi) == OK)
  6309.     {
  6310.         ForbidDOS();
  6311.         result = access(name,modes);
  6312.         PermitDOS();
  6313.  
  6314.         UnmangleName(&name,&mi);
  6315.     }
  6316.  
  6317.     RETURN(result);
  6318.     return(result);
  6319. }
  6320.  
  6321. /******************************************************************************/
  6322.  
  6323. STATIC VOID
  6324. MapIoErrToErrno(VOID)
  6325. {
  6326.     /* This routine maps AmigaDOS error codes to
  6327.      * Unix error codes, as far as this is possible.
  6328.      * This table contains AmigaDOS error codes
  6329.      * the emulated routines won't generate. I have
  6330.      * included them for the sake of completeness.
  6331.      */
  6332.     struct { LONG IoErr; LONG errno; } MapTable[] =
  6333.     {
  6334.         ERROR_NO_FREE_STORE,            ENOMEM,
  6335.         ERROR_TASK_TABLE_FULL,            ENOMEM,
  6336.         ERROR_BAD_TEMPLATE,                EINVAL,
  6337.         ERROR_BAD_NUMBER,                EINVAL,
  6338.         ERROR_REQUIRED_ARG_MISSING,        EINVAL,
  6339.         ERROR_KEY_NEEDS_ARG,            EINVAL,
  6340.         ERROR_TOO_MANY_ARGS,            EINVAL,
  6341.         ERROR_UNMATCHED_QUOTES,            EINVAL,
  6342.         ERROR_LINE_TOO_LONG,            ENAMETOOLONG,
  6343.         ERROR_FILE_NOT_OBJECT,            ENOEXEC,
  6344.         ERROR_INVALID_RESIDENT_LIBRARY,    EIO,
  6345.         ERROR_NO_DEFAULT_DIR,            EIO,
  6346.         ERROR_OBJECT_IN_USE,            EBUSY,
  6347.         ERROR_OBJECT_EXISTS,            EBUSY,
  6348.         ERROR_DIR_NOT_FOUND,            ENOENT,
  6349.         ERROR_OBJECT_NOT_FOUND,            ENOENT,
  6350.         ERROR_BAD_STREAM_NAME,            EINVAL,
  6351.         ERROR_OBJECT_TOO_LARGE,            EFBIG,
  6352.         ERROR_ACTION_NOT_KNOWN,            ENOSYS,
  6353.         ERROR_INVALID_COMPONENT_NAME,    EINVAL,
  6354.         ERROR_INVALID_LOCK,                EBADF,
  6355.         ERROR_OBJECT_WRONG_TYPE,        EFTYPE,
  6356.         ERROR_DISK_NOT_VALIDATED,        EROFS,
  6357.         ERROR_DISK_WRITE_PROTECTED,        EROFS,
  6358.         ERROR_RENAME_ACROSS_DEVICES,    EXDEV,
  6359.         ERROR_DIRECTORY_NOT_EMPTY,        ENOTEMPTY,
  6360.         ERROR_TOO_MANY_LEVELS,            ENAMETOOLONG,
  6361.         ERROR_DEVICE_NOT_MOUNTED,        ENXIO,
  6362.         ERROR_SEEK_ERROR,                EIO,
  6363.         ERROR_COMMENT_TOO_BIG,            ENAMETOOLONG,
  6364.         ERROR_DISK_FULL,                ENOSPC,
  6365.         ERROR_DELETE_PROTECTED,            EACCES,
  6366.         ERROR_WRITE_PROTECTED,            EACCES,
  6367.         ERROR_READ_PROTECTED,            EACCES,
  6368.         ERROR_NOT_A_DOS_DISK,            EFTYPE,
  6369.         ERROR_NO_DISK,                    EACCES,
  6370.         ERROR_NO_MORE_ENTRIES,            EIO,
  6371.         ERROR_IS_SOFT_LINK,                EFTYPE,
  6372.         ERROR_OBJECT_LINKED,            EIO,
  6373.         ERROR_BAD_HUNK,                    ENOEXEC,
  6374.         ERROR_NOT_IMPLEMENTED,            ENOSYS,
  6375.         ERROR_RECORD_NOT_LOCKED,        EIO,
  6376.         ERROR_LOCK_COLLISION,            EACCES,
  6377.         ERROR_LOCK_TIMEOUT,                EIO,
  6378.         ERROR_UNLOCK_ERROR,                EIO,
  6379.         ERROR_BUFFER_OVERFLOW,            EIO,
  6380.         ERROR_BREAK,                    EINTR,
  6381.         ERROR_NOT_EXECUTABLE,            ENOEXEC
  6382.     };
  6383.  
  6384.     LONG ioErr = IoErr();
  6385.     int i;
  6386.  
  6387.     /* If nothing else matches, we can always
  6388.      * flag it as an I/O error.
  6389.      */
  6390.     errno = EIO;
  6391.  
  6392.     for(i = 0 ; i < NUM_ENTRIES(MapTable) ; i++)
  6393.     {
  6394.         if(MapTable[i].IoErr == ioErr)
  6395.         {
  6396.             errno = MapTable[i].errno;
  6397.             break;
  6398.         }
  6399.     }
  6400. }
  6401.  
  6402. /******************************************************************************/
  6403.  
  6404. off_t
  6405. amiga_lseek(int fd,off_t offset,int mode)
  6406. {
  6407.     struct UFB * ufb;
  6408.     off_t result = ERROR;
  6409.  
  6410.     ENTER();
  6411.     SHOWVALUE(fd);
  6412.     SHOWVALUE(offset);
  6413.     SHOWVALUE(mode);
  6414.  
  6415.     ForbidDOS();
  6416.  
  6417.     /* Make sure that we operate on a file. */
  6418.     ufb = chkufb(fd);
  6419.     if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  6420.         result = lseek(fd,offset,mode);
  6421.     else
  6422.         errno = EBADF;
  6423.  
  6424.     PermitDOS();
  6425.  
  6426.     RETURN(result);
  6427.     return(result);
  6428. }
  6429.  
  6430. /******************************************************************************/
  6431.  
  6432. int
  6433. amiga_chroot(char *name)    /* dummy */
  6434. {
  6435.     int result = OK;
  6436.  
  6437.     ENTER();
  6438.  
  6439.     SHOWSTRING(name);
  6440.  
  6441.     RETURN(result);
  6442.     return(result);
  6443. }
  6444.  
  6445. /******************************************************************************/
  6446.  
  6447. STATIC int
  6448. MapFileNameAmigaToUnix(
  6449.     const char *    amiga,
  6450.     char *            unix,
  6451.     int                maxUnixLen)
  6452. {
  6453.     int len,destLen;
  6454.     int result = ERROR;
  6455.  
  6456.     /* This routine makes a Unix file
  6457.      * name generated from an AmigaDOS
  6458.      * file name. This involves a slight
  6459.      * change of syntax...
  6460.      */
  6461.     D(("amiga name |%s|",amiga));
  6462.  
  6463.     len = destLen = strlen(amiga);
  6464.     if(amiga[0] == '/')
  6465.     {
  6466.         destLen = 2 + len;
  6467.     }
  6468.     else
  6469.     {
  6470.         int i;
  6471.  
  6472.         for(i = 0 ; i < len ; i++)
  6473.         {
  6474.             if(amiga[i] == ':')
  6475.             {
  6476.                 if(amiga[i+1] != '\0')
  6477.                     destLen = 1 + len;
  6478.  
  6479.                 break;
  6480.             }
  6481.         }
  6482.     }
  6483.  
  6484.     if(destLen < maxUnixLen)
  6485.     {
  6486.         if(amiga[0] == '/')
  6487.         {
  6488.             /* `/foo\0' -> `../foo\0' */
  6489.             memmove(&unix[2],amiga,len+1);
  6490.             strncpy(unix,"..",2);
  6491.         }
  6492.         else
  6493.         {
  6494.             BOOL done = FALSE;
  6495.             int i;
  6496.  
  6497.             for(i = 0 ; i < len ; i++)
  6498.             {
  6499.                 if(amiga[i] == ':')
  6500.                 {
  6501.                     if(amiga[i+1] == '\0')
  6502.                     {
  6503.                         /* `foo:\0' -> `/foo\0' */
  6504.                         memmove(&unix[1],amiga,i);
  6505.                         unix[0] = '/';
  6506.                         unix[i+1] = '\0';
  6507.                     }
  6508.                     else
  6509.                     {
  6510.                         /* `foo:bar\0' -> `/foo/bar\0' */
  6511.                         memmove(&unix[1],amiga,len+1);
  6512.                         unix[0] = '/';
  6513.                         unix[i+1] = '/';
  6514.                     }
  6515.  
  6516.                     done = TRUE;
  6517.                     break;
  6518.                 }
  6519.             }
  6520.  
  6521.             if(NOT done && unix != amiga)
  6522.                 strcpy(unix,amiga);
  6523.         }
  6524.  
  6525.         D(("unix name |%s|",unix));
  6526.  
  6527.         result = OK;
  6528.     }
  6529.     else
  6530.     {
  6531.         SHOWMSG("unix name is too long to fit");
  6532.  
  6533.         errno = ENAMETOOLONG;
  6534.     }
  6535.  
  6536.     return(result);
  6537. }
  6538.  
  6539. /******************************************************************************/
  6540.  
  6541. STATIC VOID
  6542. FlushSTDOUT(VOID)
  6543. {
  6544.     /* Flush the standard output streams so that
  6545.      * any following output will be printed after
  6546.      * any buffered stdio output.
  6547.      */
  6548.     if(WBenchMsg == NULL)
  6549.     {
  6550.         struct UFB * ufb;
  6551.  
  6552.         /* Don't let anybody stop us. */
  6553.         signal(SIGINT,SIG_IGN);
  6554.         signal(SIGTERM,SIG_IGN);
  6555.  
  6556.         ufb = chkufb(fileno(stdout));
  6557.         if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  6558.             fflush(stdout);
  6559.  
  6560.         ufb = chkufb(fileno(stderr));
  6561.         if(ufb != NULL && FLAG_IS_CLEAR(ufb->ufbflg,UFB_IS_SOCKET))
  6562.             fflush(stderr);
  6563.     }
  6564. }
  6565.  
  6566. VOID
  6567. _CXOVF(VOID)
  6568. {
  6569.     /* This routine is called when a stack overflow occurs. */
  6570.     FlushSTDOUT();
  6571.     ReportProblem("Stack overflow");
  6572.  
  6573.     exit(RETURN_ERROR);
  6574. }
  6575.  
  6576. VOID __regargs
  6577. _CXBRK(VOID)
  6578. {
  6579.     extern STRPTR _ProgramName;
  6580.  
  6581.     FlushSTDOUT();
  6582.  
  6583.     /* This routine is called when the program is interrupted. */
  6584.     if(DOSBase->lib_Version >= 37)
  6585.     {
  6586.         PrintFault(ERROR_BREAK,_ProgramName);
  6587.     }
  6588.     else
  6589.     {
  6590.         const char *famousLastWords = ": *** Break";
  6591.         BPTR output = Output();
  6592.  
  6593.         Write(output,(APTR)famousLastWords,strlen(famousLastWords));
  6594.         Write(output,_ProgramName,strlen(_ProgramName));
  6595.         Write(output,"\n",1);
  6596.     }
  6597.  
  6598.     exit(RETURN_WARN);
  6599. }
  6600.  
  6601. /******************************************************************************/
  6602.  
  6603. STATIC STRPTR SambaSemaphoreName = "Amiga Samba";
  6604.  
  6605. struct SambaClientNode
  6606. {
  6607.     struct MinNode    scn_MinNode;
  6608.     struct Task *    scn_Task;
  6609.     pid_t            scn_PID;
  6610. };
  6611.  
  6612. struct SambaSemaphore
  6613. {
  6614.     struct SignalSemaphore    ss_Semaphore;
  6615.     struct List                ss_ClientList;
  6616.     pid_t                    ss_PID;
  6617.     struct List                ss_FileLockList;
  6618. };
  6619.  
  6620. STATIC struct SambaSemaphore *    SambaSemaphore;
  6621. STATIC struct SambaClientNode *    ThisClient;
  6622.  
  6623. STATIC VOID
  6624. CleanupSambaSemaphore(VOID)
  6625. {
  6626.     if(ThisClient != NULL)
  6627.     {
  6628.         /* Unregister the program. */
  6629.         ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6630.         Remove((struct Node *)ThisClient);
  6631.         ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6632.  
  6633.         FreeVec(ThisClient);
  6634.         ThisClient = NULL;
  6635.     }
  6636. }
  6637.  
  6638. STATIC BOOL
  6639. SetupSambaSemaphore(VOID)
  6640. {
  6641.     BOOL success = FALSE;
  6642.  
  6643.     /* We have to have the timer open to serialize the process IDs properly. */
  6644.     if(TimerBase != NULL)
  6645.     {
  6646.         Forbid();
  6647.  
  6648.         /* Try to find the global rendezvous semaphore. */
  6649.         SambaSemaphore = (struct SambaSemaphore *)FindSemaphore(SambaSemaphoreName);
  6650.         if(SambaSemaphore == NULL)
  6651.         {
  6652.             /* Couldn't find it. So, we create it... */
  6653.             SambaSemaphore = AllocMem(sizeof(*SambaSemaphore) + strlen(SambaSemaphoreName)+1,MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  6654.             if(SambaSemaphore != NULL)
  6655.             {
  6656.                 /* Set up the name. */
  6657.                 SambaSemaphore->ss_Semaphore.ss_Link.ln_Name = (char *)(SambaSemaphore+1);
  6658.                 strcpy(SambaSemaphore->ss_Semaphore.ss_Link.ln_Name,SambaSemaphoreName);
  6659.  
  6660.                 /* Set the base value for all process IDs. */
  6661.                 SambaSemaphore->ss_PID = 936;
  6662.  
  6663.                 /* Clear the client list tasks are going to be registered with. */
  6664.                 NewList(&SambaSemaphore->ss_ClientList);
  6665.  
  6666.                 /* Clear the list we will use for keeping
  6667.                  * track of file segment locks.
  6668.                  */
  6669.                 NewList(&SambaSemaphore->ss_FileLockList);
  6670.  
  6671.                 AddSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6672.             }
  6673.         }
  6674.  
  6675.         Permit();
  6676.     }
  6677.  
  6678.     /* If possible, register this task. */
  6679.     if(SambaSemaphore != NULL)
  6680.     {
  6681.         struct SambaClientNode * scn;
  6682.  
  6683.         scn = AllocVec(sizeof(*scn),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  6684.         if(scn != NULL)
  6685.         {
  6686.             LONG max_cli,i;
  6687.  
  6688.             /* That's me. */
  6689.             scn->scn_Task = FindTask(NULL);
  6690.  
  6691.             /* Now for the interesting part: assign a PID to this
  6692.              * process which matches its CLI task number.
  6693.              */
  6694.             Forbid();
  6695.  
  6696.             max_cli = MaxCli();
  6697.             for(i = 1 ; i <= max_cli ; i++)
  6698.             {
  6699.                 if(FindCliProc(i) == (struct Process *)scn->scn_Task)
  6700.                 {
  6701.                     scn->scn_PID = i;
  6702.                     break;
  6703.                 }
  6704.             }
  6705.  
  6706.             Permit();
  6707.  
  6708.             ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6709.             AddTail(&SambaSemaphore->ss_ClientList,(struct Node *)scn);
  6710.             ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6711.  
  6712.             ThisClient = scn;
  6713.  
  6714.             success = TRUE;
  6715.         }
  6716.     }
  6717.  
  6718.     return(success);
  6719. }
  6720.  
  6721. int
  6722. amiga_kill(pid_t pid,int sig)
  6723. {
  6724.     struct SambaClientNode * scn;
  6725.     struct Task * found = NULL;
  6726.     int result = ERROR;
  6727.  
  6728.     chkabort();
  6729.  
  6730.     ENTER();
  6731.  
  6732.     ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6733.  
  6734.     /* Try to find the Samba program that responds
  6735.      * to the given process ID.
  6736.      */
  6737.     for(scn = (struct SambaClientNode *)SambaSemaphore->ss_ClientList.lh_Head ;
  6738.         scn->scn_MinNode.mln_Succ != NULL ;
  6739.         scn = (struct SambaClientNode *)scn->scn_MinNode.mln_Succ)
  6740.     {
  6741.         if(scn->scn_PID == pid)
  6742.         {
  6743.             found = scn->scn_Task;
  6744.             break;
  6745.         }
  6746.     }
  6747.  
  6748.     /* Did we find one? */
  6749.     if(found != NULL)
  6750.     {
  6751.         /* Kill the task or just do nothing? */
  6752.         if(sig == SIGTERM)
  6753.             Signal(found,SIGBREAKF_CTRL_C);
  6754.  
  6755.         result = OK;
  6756.     }
  6757.     else
  6758.     {
  6759.         errno = ESRCH;
  6760.     }
  6761.  
  6762.     ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  6763.  
  6764.     RETURN(result);
  6765.     return(result);
  6766. }
  6767.  
  6768. pid_t
  6769. amiga_getpid(VOID)
  6770. {
  6771.     pid_t result;
  6772.  
  6773.     chkabort();
  6774.  
  6775.     ENTER();
  6776.  
  6777.     /* Return this program's process ID. */
  6778.     result = ThisClient->scn_PID;
  6779.  
  6780.     RETURN(result);
  6781.     return(result);
  6782. }
  6783.  
  6784. /******************************************************************************/
  6785.  
  6786. struct LockedRegionNode
  6787. {
  6788.     struct MinNode    lrn_MinNode;
  6789.     LONG            lrn_Start;
  6790.     LONG            lrn_Stop;
  6791.     pid_t            lrn_Owner;
  6792.     BOOL            lrn_Shared;
  6793. };
  6794.  
  6795. struct FileLockNode
  6796. {
  6797.     struct MinNode    fln_MinNode;
  6798.     struct List        fln_LockedRegionList;
  6799.     BPTR            fln_FileParentDir;
  6800.     UBYTE            fln_FileName[1];
  6801. };
  6802.  
  6803. STATIC VOID
  6804. RemoveLockedRegionNode(struct UFB * ufb,LONG start,LONG stop)
  6805. {
  6806.     if(FLAG_IS_SET(ufb->ufbflg,UFB_LOCKED))
  6807.     {
  6808.         BPTR fileHandle = (BPTR)ufb->ufbfh;
  6809.         struct FileLockNode * whichLock;
  6810.  
  6811.         /* Find the locked file this descriptor
  6812.          * buffer belongs to.
  6813.          */
  6814.         if(FindFileLockNodeByFileHandle(fileHandle,&whichLock) == OK && whichLock != NULL)
  6815.         {
  6816.             struct LockedRegionNode * lrn;
  6817.  
  6818.             /* Find the region to unlock and remove it. */
  6819.             for(lrn = (struct LockedRegionNode *)whichLock->fln_LockedRegionList.lh_Head ;
  6820.                 lrn->lrn_MinNode.mln_Succ != NULL ;
  6821.                 lrn = (struct LockedRegionNode *)lrn->lrn_MinNode.mln_Succ)
  6822.             {
  6823.                 if(lrn->lrn_Owner == ThisClient->scn_PID &&
  6824.                    lrn->lrn_Start == start &&
  6825.                    lrn->lrn_Stop  == stop)
  6826.                 {
  6827.                     SHOWMSG("unlocking all regions on this file");
  6828.  
  6829.                     Remove((struct Node *)lrn);
  6830.                     DeleteLockedRegionNode(lrn);
  6831.                     break;
  6832.                 }
  6833.             }
  6834.  
  6835.             /* Check if there are any locked regions left.
  6836.              * If not, mark the entire file as unlocked.
  6837.              */
  6838.             if(IsListEmpty(&whichLock->fln_LockedRegionList))
  6839.             {
  6840.                 SHOWMSG("no more regions are locked; removing the file lock node");
  6841.  
  6842.                 Remove((struct Node *)whichLock);
  6843.  
  6844.                 DeleteFileLockNode(whichLock);
  6845.  
  6846.                 CLEAR_FLAG(ufb->ufbflg,UFB_LOCKED);
  6847.             }
  6848.         }
  6849.     }
  6850. }
  6851.  
  6852. STATIC VOID
  6853. DeleteLockedRegionNode(struct LockedRegionNode * lrn)
  6854. {
  6855.     if(lrn != NULL)
  6856.         FreeMem(lrn,sizeof(*lrn));
  6857. }
  6858.  
  6859. STATIC LONG
  6860. CreateLockedRegionNode(struct LockedRegionNode ** resultPtr)
  6861. {
  6862.     struct LockedRegionNode * lrn;
  6863.     LONG error;
  6864.  
  6865.     lrn = AllocMem(sizeof(*lrn),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  6866.     if(lrn != NULL)
  6867.     {
  6868.         lrn->lrn_Owner = ThisClient->scn_PID;
  6869.  
  6870.         error = OK;
  6871.     }
  6872.     else
  6873.     {
  6874.         error = ERROR_NO_FREE_STORE;
  6875.     }
  6876.  
  6877.     (*resultPtr) = lrn;
  6878.  
  6879.     return(error);
  6880. }
  6881.  
  6882. STATIC VOID
  6883. DeleteFileLockNode(struct FileLockNode * fln)
  6884. {
  6885.     if(fln != NULL)
  6886.     {
  6887.         UnLock(fln->fln_FileParentDir);
  6888.         FreeVec(fln);
  6889.     }
  6890. }
  6891.  
  6892. STATIC LONG
  6893. CreateFileLockNode(struct UFB * ufb,struct FileLockNode ** resultPtr)
  6894. {
  6895.     struct FileLockNode * result = NULL;
  6896.     BPTR fileHandle = (BPTR)ufb->ufbfh;
  6897.     D_S(struct FileInfoBlock,fib);
  6898.     LONG error = OK;
  6899.  
  6900.     /* We store a lock on the file's parent directory
  6901.      * and the name of the file for later use in
  6902.      * comparisons.
  6903.      */
  6904.     if(ExamineFH(fileHandle,fib))
  6905.     {
  6906.         struct FileLockNode * fln;
  6907.  
  6908.         fln = AllocVec(sizeof(*fln) + strlen(fib->fib_FileName),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  6909.         if(fln != NULL)
  6910.         {
  6911.             fln->fln_FileParentDir = ParentOfFH(fileHandle);
  6912.             if(fln->fln_FileParentDir != ZERO)
  6913.             {
  6914.                 strcpy(fln->fln_FileName,fib->fib_FileName);
  6915.  
  6916.                 NewList(&fln->fln_LockedRegionList);
  6917.  
  6918.                 result = fln;
  6919.                 fln = NULL;
  6920.             }
  6921.             else
  6922.             {
  6923.                 error = IoErr();
  6924.             }
  6925.  
  6926.             DeleteFileLockNode(fln);
  6927.         }
  6928.         else
  6929.         {
  6930.             error = ERROR_NO_FREE_STORE;
  6931.         }
  6932.     }
  6933.     else
  6934.     {
  6935.         error = IoErr();
  6936.     }
  6937.  
  6938.     (*resultPtr) = result;
  6939.  
  6940.     return(error);
  6941. }
  6942.  
  6943. STATIC LONG
  6944. FindFileLockNodeByFileHandle(BPTR fileHandle,struct FileLockNode ** resultPtr)
  6945. {
  6946.     struct FileLockNode * result = NULL;
  6947.     BPTR parentDir;
  6948.     LONG error;
  6949.  
  6950.     /* Determine the file's parent directory and
  6951.      * name. These will be compared against the
  6952.      * global file lock data.
  6953.      */
  6954.     parentDir = ParentOfFH(fileHandle);
  6955.     if(parentDir != ZERO)
  6956.     {
  6957.         D_S(struct FileInfoBlock,this_fib);
  6958.  
  6959.         if(ExamineFH(fileHandle,this_fib))
  6960.         {
  6961.             struct FileLockNode * fln;
  6962.  
  6963.             #if DEBUG
  6964.             {
  6965.                 char name[MAX_FILENAME_LEN];
  6966.  
  6967.                 if(NameFromFH(fileHandle,name,sizeof(name)))
  6968.                     D(("Looking for a lock on file |%s|",name));
  6969.             }
  6970.             #endif /* DEBUG */
  6971.  
  6972.             error = OK;
  6973.  
  6974.             for(fln = (struct FileLockNode *)SambaSemaphore->ss_FileLockList.lh_Head ;
  6975.                 fln->fln_MinNode.mln_Succ != NULL ;
  6976.                 fln = (struct FileLockNode *)fln->fln_MinNode.mln_Succ)
  6977.             {
  6978.                 /* To be identical, the files must reside in the
  6979.                  * same directories and bear the same names.
  6980.                  */
  6981.                 if(SameLock(fln->fln_FileParentDir,parentDir) == LOCK_SAME)
  6982.                 {
  6983.                     if(Stricmp(fln->fln_FileName,this_fib->fib_FileName) == SAME)
  6984.                     {
  6985.                         result = fln;
  6986.                         error = OK;
  6987.  
  6988.                         break;
  6989.                     }
  6990.                 }
  6991.             }
  6992.         }
  6993.         else
  6994.         {
  6995.             error = IoErr();
  6996.         }
  6997.  
  6998.         if(result != NULL)
  6999.             SHOWMSG("found one");
  7000.         else
  7001.             SHOWMSG("didn't find one");
  7002.  
  7003.         UnLock(parentDir);
  7004.     }
  7005.     else
  7006.     {
  7007.         error = IoErr();
  7008.     }
  7009.  
  7010.     (*resultPtr) = result;
  7011.  
  7012.     return(error);
  7013. }
  7014.  
  7015. STATIC VOID
  7016. FindFileLockNodeByDrawerAndName(BPTR dirLock,STRPTR fileName,struct FileLockNode ** resultPtr)
  7017. {
  7018.     struct FileLockNode * result = NULL;
  7019.     struct FileLockNode * fln;
  7020.  
  7021.     /* This is a somewhat simplied version of FindFileLockNodeByFileHandle()
  7022.      * which works with preset drawer and name data.
  7023.      */
  7024.  
  7025.     #if DEBUG
  7026.     {
  7027.         char name[MAX_FILENAME_LEN];
  7028.  
  7029.         if(NameFromLock(dirLock,name,sizeof(name)))
  7030.         {
  7031.             if(AddPart(name,fileName,sizeof(name)))
  7032.                 D(("Looking for a lock on file |%s|",name));
  7033.         }
  7034.     }
  7035.     #endif /* DEBUG */
  7036.  
  7037.     for(fln = (struct FileLockNode *)SambaSemaphore->ss_FileLockList.lh_Head ;
  7038.         fln->fln_MinNode.mln_Succ != NULL ;
  7039.         fln = (struct FileLockNode *)fln->fln_MinNode.mln_Succ)
  7040.     {
  7041.         if(SameLock(fln->fln_FileParentDir,dirLock) == LOCK_SAME)
  7042.         {
  7043.             if(Stricmp(fln->fln_FileName,fileName) == SAME)
  7044.             {
  7045.                 result = fln;
  7046.  
  7047.                 break;
  7048.             }
  7049.         }
  7050.     }
  7051.  
  7052.     if(result != NULL)
  7053.         SHOWMSG("found one");
  7054.     else
  7055.         SHOWMSG("didn't find one");
  7056.  
  7057.     (*resultPtr) = result;
  7058. }
  7059.  
  7060. STATIC struct LockedRegionNode *
  7061. FindCollidingRegion(struct FileLockNode * fln,LONG start,LONG stop,BOOL shared)
  7062. {
  7063.     struct LockedRegionNode * result = NULL;
  7064.     struct LockedRegionNode * lrn;
  7065.  
  7066.     /* This routine looks for a locked region that overlaps
  7067.      * with the specified region. It returns a pointer to the
  7068.      * region that would collide with the specified region if
  7069.      * a new lock were to be added.
  7070.      */
  7071.     for(lrn = (struct LockedRegionNode *)fln->fln_LockedRegionList.lh_Head ;
  7072.         lrn->lrn_MinNode.mln_Succ != NULL ;
  7073.         lrn = (struct LockedRegionNode *)lrn->lrn_MinNode.mln_Succ)
  7074.     {
  7075.         /* Do the regions overlap? */
  7076.         if(lrn->lrn_Start <= stop && start <= lrn->lrn_Stop)
  7077.         {
  7078.             /* Two shared regions may always overlap.
  7079.              * How about the rest?
  7080.              */
  7081.             if(NOT shared || NOT lrn->lrn_Shared)
  7082.             {
  7083.                 /* The lock owner may add as many exclusive
  7084.                  * or shared locks to the same region as
  7085.                  * necessary.
  7086.                  */
  7087.                 if(lrn->lrn_Owner == ThisClient->scn_PID)
  7088.                     continue;
  7089.  
  7090.                 /* So we found a region that would
  7091.                  * cause a collision.
  7092.                  */
  7093.                 result = lrn;
  7094.                 break;
  7095.             }
  7096.         }
  7097.     }
  7098.  
  7099.     return(result);
  7100. }
  7101.  
  7102. STATIC VOID
  7103. CleanupFileLocks(int fd)
  7104. {
  7105.     struct UFB * ufb;
  7106.  
  7107.     /* This routine removes all locked regions from a file
  7108.      * before it is eventually closed.
  7109.      */
  7110.  
  7111.     ufb = chkufb(fd);
  7112.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_LOCKED))
  7113.     {
  7114.         BPTR fileHandle = (BPTR)ufb->ufbfh;
  7115.         struct FileLockNode * whichLock;
  7116.  
  7117.         ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7118.  
  7119.         if(FindFileLockNodeByFileHandle(fileHandle,&whichLock) == OK && whichLock != NULL)
  7120.         {
  7121.             struct LockedRegionNode * lrn_this;
  7122.             struct LockedRegionNode * lrn_next;
  7123.  
  7124.             SHOWMSG("unlocking all regions on this file");
  7125.  
  7126.             for(lrn_this = (struct LockedRegionNode *)whichLock->fln_LockedRegionList.lh_Head ;
  7127.                (lrn_next = (struct LockedRegionNode *)lrn_this->lrn_MinNode.mln_Succ) != NULL ;
  7128.                 lrn_this = lrn_next)
  7129.             {
  7130.                 if(lrn_this->lrn_Owner == ThisClient->scn_PID)
  7131.                 {
  7132.                     Remove((struct Node *)lrn_this);
  7133.                     DeleteLockedRegionNode(lrn_this);
  7134.                 }
  7135.             }
  7136.  
  7137.             if(IsListEmpty(&whichLock->fln_LockedRegionList))
  7138.             {
  7139.                 SHOWMSG("no more regions are locked; removing the file lock node");
  7140.  
  7141.                 Remove((struct Node *)whichLock);
  7142.  
  7143.                 DeleteFileLockNode(whichLock);
  7144.             }
  7145.         }
  7146.  
  7147.         CLEAR_FLAG(ufb->ufbflg,UFB_LOCKED);
  7148.  
  7149.         ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7150.     }
  7151. }
  7152.  
  7153. #define SEEK_ERROR (-1)
  7154.  
  7155. STATIC int
  7156. HandleFileLocking(int cmd,struct flock * l,struct UFB * ufb)
  7157. {
  7158.     int result = ERROR;
  7159.  
  7160.     /* This routine implements advisory file segment locking
  7161.      * similar to 4.4BSD, but not quite the same. The functionality
  7162.      * is a subset, somewhat similar to the functionality offered
  7163.      * by the AmigaDOS LockRecord() and UnlockRecord() functions.
  7164.      * This means for example that every unlock request must
  7165.      * match the size and position of the corresponding locking
  7166.      * request.
  7167.      *
  7168.      * This implementation was chosen because not every Amiga
  7169.      * filing system implements record locking and Samba
  7170.      * absolutely requires this functionality to work.
  7171.      */
  7172.     if(l != NULL && ufb != NULL)
  7173.     {
  7174.         /* Can we make sense of the input parameters? */
  7175.         if(F_RDLCK <= l->l_type && l->l_type <= F_WRLCK &&
  7176.           (l->l_whence == SEEK_SET || l->l_whence == SEEK_CUR || l->l_whence == SEEK_END))
  7177.         {
  7178.             struct LockedRegionNode * lrn = NULL;
  7179.             struct FileLockNode * fln = NULL;
  7180.             LONG error;
  7181.  
  7182.             if((cmd == F_SETLK || cmd == F_SETLKW) && (l->l_type != F_UNLCK))
  7183.             {
  7184.                 SHOWMSG("this is a lock request");
  7185.                 error = CreateFileLockNode(ufb,&fln);
  7186.                 if(error == OK)
  7187.                     error = CreateLockedRegionNode(&lrn);
  7188.             }
  7189.             else
  7190.             {
  7191.                 SHOWMSG("this is not a lock request");
  7192.                 error = OK;
  7193.             }
  7194.  
  7195.             if(error == OK)
  7196.             {
  7197.                 D_S(struct FileInfoBlock,fib);
  7198.                 BPTR fileHandle = (BPTR)ufb->ufbfh;
  7199.                 BOOL dataIsValid = TRUE;
  7200.                 LONG currentPosition;
  7201.                 LONG start = 0;
  7202.                 LONG len = 0;
  7203.  
  7204.                 /* Now calculate the position of the
  7205.                  * first byte to lock and the number
  7206.                  * of bytes to lock.
  7207.                  */
  7208.                 switch(l->l_whence)
  7209.                 {
  7210.                     case SEEK_SET:
  7211.  
  7212.                         start = l->l_start;
  7213.  
  7214.                         if(l->l_len == 0)
  7215.                         {
  7216.                             if(ExamineFH(fileHandle,fib))
  7217.                                 len = fib->fib_Size - start;
  7218.                             else
  7219.                                 dataIsValid = FALSE;
  7220.                         }
  7221.                         else
  7222.                         {
  7223.                             len = l->l_len;
  7224.                         }
  7225.  
  7226.                         break;
  7227.  
  7228.                     case SEEK_CUR:
  7229.  
  7230.                         currentPosition = Seek(fileHandle,0,OFFSET_CURRENT);
  7231.                         if(currentPosition != SEEK_ERROR)
  7232.                         {
  7233.                             start = currentPosition + l->l_start;
  7234.  
  7235.                             if(l->l_len == 0)
  7236.                             {
  7237.                                 if(ExamineFH(fileHandle,fib))
  7238.                                     len = fib->fib_Size - start;
  7239.                                 else
  7240.                                     dataIsValid = FALSE;
  7241.                             }
  7242.                             else
  7243.                             {
  7244.                                 len = l->l_len;
  7245.                             }
  7246.                         }
  7247.                         else
  7248.                         {
  7249.                             dataIsValid = FALSE;
  7250.                         }
  7251.  
  7252.                         break;
  7253.  
  7254.                     case SEEK_END:
  7255.                     default:
  7256.  
  7257.                         if(ExamineFH(fileHandle,fib))
  7258.                         {
  7259.                             start = fib->fib_Size + l->l_start;
  7260.  
  7261.                             if(l->l_len == 0)
  7262.                                 len = fib->fib_Size - start;
  7263.                             else
  7264.                                 len = l->l_len;
  7265.                         }
  7266.                         else
  7267.                         {
  7268.                             dataIsValid = FALSE;
  7269.                         }
  7270.  
  7271.                         break;
  7272.                 }
  7273.  
  7274.                 SHOWVALUE(start);
  7275.                 SHOWVALUE(len);
  7276.  
  7277.                 /* Did we get everything we needed? */
  7278.                 if(dataIsValid)
  7279.                 {
  7280.                     if(start >= 0 && len >= 0)
  7281.                     {
  7282.                         if(len > 0)
  7283.                         {
  7284.                             if(l->l_type == F_UNLCK)
  7285.                             {
  7286.                                 D(("unlocking %ld..%ld",start,start+len-1));
  7287.  
  7288.                                 ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7289.  
  7290.                                 RemoveLockedRegionNode(ufb,start,start+len-1);
  7291.  
  7292.                                 ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7293.  
  7294.                                 result = OK;
  7295.                             }
  7296.                             else if(cmd == F_SETLKW)
  7297.                             {
  7298.                                 BPTR parentDir;
  7299.  
  7300.                                 D(("  locking %ld..%ld",start,start+len-1));
  7301.  
  7302.                                 parentDir = ParentOfFH(fileHandle);
  7303.                                 if(parentDir != ZERO)
  7304.                                 {
  7305.                                     D_S(struct FileInfoBlock,fib);
  7306.  
  7307.                                     if(ExamineFH(fileHandle,fib))
  7308.                                     {
  7309.                                         BOOL shared = (BOOL)(l->l_type == F_RDLCK);
  7310.                                         struct FileLockNode * existing_fln;
  7311.                                         BOOL stopped = FALSE;
  7312.                                         BOOL locked;
  7313.  
  7314.                                         if(shared)
  7315.                                             D(("this is a shared lock; waiting for completion"));
  7316.                                         else
  7317.                                             D(("this is an exclusive lock; waiting for completion"));
  7318.  
  7319.                                         lrn->lrn_Start    = start;
  7320.                                         lrn->lrn_Stop    = start+len-1;
  7321.                                         lrn->lrn_Shared    = shared;
  7322.  
  7323.                                         /* Retry until we manage to lock the record. */
  7324.                                         locked = FALSE;
  7325.                                         do
  7326.                                         {
  7327.                                             ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7328.  
  7329.                                             FindFileLockNodeByDrawerAndName(parentDir,fib->fib_FileName,&existing_fln);
  7330.                                             if(existing_fln != NULL)
  7331.                                             {
  7332.                                                 SHOWMSG("that file is already locked by someone");
  7333.  
  7334.                                                 if(FindCollidingRegion(existing_fln,start,start+len-1,shared) == NULL)
  7335.                                                 {
  7336.                                                     SHOWMSG("but the locks don't collide");
  7337.  
  7338.                                                     AddTail(&existing_fln->fln_LockedRegionList,(struct Node *)lrn);
  7339.                                                     lrn = NULL;
  7340.  
  7341.                                                     locked = TRUE;
  7342.                                                 }
  7343.                                                 else
  7344.                                                 {
  7345.                                                     SHOWMSG("and the locks collide");
  7346.                                                 }
  7347.                                             }
  7348.                                             else
  7349.                                             {
  7350.                                                 SHOWMSG("nobody has any locks on this file");
  7351.  
  7352.                                                 AddTail(&SambaSemaphore->ss_FileLockList,(struct Node *)fln);
  7353.                                                 AddTail(&fln->fln_LockedRegionList,(struct Node *)lrn);
  7354.  
  7355.                                                 fln = NULL;
  7356.                                                 lrn = NULL;
  7357.  
  7358.                                                 locked = TRUE;
  7359.                                             }
  7360.  
  7361.                                             ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7362.  
  7363.                                             if(NOT locked)
  7364.                                             {
  7365.                                                 const int randMax = RAND_MAX / 65536;
  7366.                                                 LONG numRandomTicks;
  7367.  
  7368.                                                 if(CheckAbort())
  7369.                                                 {
  7370.                                                     stopped = TRUE;
  7371.                                                     break;
  7372.                                                 }
  7373.  
  7374.                                                 /* Wait a little before retrying
  7375.                                                  * the locking operation. We add
  7376.                                                  * a little randomness here to
  7377.                                                  * reduce the likelihood of two
  7378.                                                  * competing processes trying to
  7379.                                                  * lock the same file at the
  7380.                                                  * same time.
  7381.                                                  */
  7382.  
  7383.                                                 numRandomTicks = ((TICKS_PER_SECOND / 2) * (rand() / 65536)) / randMax;
  7384.  
  7385.                                                 if(numRandomTicks > 0)
  7386.                                                     Delay(numRandomTicks);
  7387.                                             }
  7388.                                         }
  7389.                                         while(NOT locked);
  7390.  
  7391.                                         if(stopped)
  7392.                                         {
  7393.                                             SHOWMSG("lock polling loop stopped");
  7394.  
  7395.                                             DeleteFileLockNode(fln);
  7396.                                             fln = NULL;
  7397.  
  7398.                                             DeleteLockedRegionNode(lrn);
  7399.                                             lrn = NULL;
  7400.  
  7401.                                             UnLock(parentDir);
  7402.                                             parentDir = ZERO;
  7403.  
  7404.                                             errno = EINTR;
  7405.  
  7406.                                             raise(SIGINT);
  7407.                                         }
  7408.  
  7409.                                         if(locked)
  7410.                                         {
  7411.                                             SHOWMSG("the file now has a lock set");
  7412.                                             SET_FLAG(ufb->ufbflg,UFB_LOCKED);
  7413.                                             result = OK;
  7414.                                         }
  7415.                                     }
  7416.                                     else
  7417.                                     {
  7418.                                         SHOWMSG("couldn't read this file's name");
  7419.                                         MapIoErrToErrno();
  7420.                                     }
  7421.  
  7422.                                     UnLock(parentDir);
  7423.                                 }
  7424.                                 else
  7425.                                 {
  7426.                                     SHOWMSG("couldn't get a lock on the file's parent directory");
  7427.                                     MapIoErrToErrno();
  7428.                                 }
  7429.                             }
  7430.                             else if(cmd == F_SETLK)
  7431.                             {
  7432.                                 BOOL shared = (BOOL)(l->l_type == F_RDLCK);
  7433.                                 struct FileLockNode * existing_fln;
  7434.                                 BOOL locked = FALSE;
  7435.  
  7436.                                 if(shared)
  7437.                                     D(("this is a shared lock"));
  7438.                                 else
  7439.                                     D(("this is an exclusive lock"));
  7440.  
  7441.                                 lrn->lrn_Start    = start;
  7442.                                 lrn->lrn_Stop    = start+len-1;
  7443.                                 lrn->lrn_Shared    = shared;
  7444.  
  7445.                                 ObtainSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7446.  
  7447.                                 if(FindFileLockNodeByFileHandle(fileHandle,&existing_fln) == OK)
  7448.                                 {
  7449.                                     if(existing_fln != NULL)
  7450.                                     {
  7451.                                         SHOWMSG("that file is already locked by someone else");
  7452.  
  7453.                                         if(FindCollidingRegion(existing_fln,start,start+len-1,shared) == NULL)
  7454.                                         {
  7455.                                             SHOWMSG("but the locks don't collide");
  7456.  
  7457.                                             AddTail(&existing_fln->fln_LockedRegionList,(struct Node *)lrn);
  7458.                                             lrn = NULL;
  7459.  
  7460.                                             locked = TRUE;
  7461.                                         }
  7462.                                         else
  7463.                                         {
  7464.                                             SHOWMSG("and the locks collide");
  7465.                                         }
  7466.                                     }
  7467.                                     else
  7468.                                     {
  7469.                                         SHOWMSG("nobody has any locks on this file");
  7470.  
  7471.                                         AddTail(&SambaSemaphore->ss_FileLockList,(struct Node *)fln);
  7472.                                         AddTail(&fln->fln_LockedRegionList,(struct Node *)lrn);
  7473.  
  7474.                                         fln = NULL;
  7475.                                         lrn = NULL;
  7476.  
  7477.                                         locked = TRUE;
  7478.                                     }
  7479.                                 }
  7480.  
  7481.                                 ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7482.  
  7483.                                 if(locked)
  7484.                                 {
  7485.                                     SHOWMSG("the file now has a lock set");
  7486.  
  7487.                                     SET_FLAG(ufb->ufbflg,UFB_LOCKED);
  7488.  
  7489.                                     result = OK;
  7490.                                 }
  7491.                                 else
  7492.                                 {
  7493.                                     errno = EACCES;
  7494.                                 }
  7495.                             }
  7496.                             else if (cmd == F_GETLK)
  7497.                             {
  7498.                                 struct FileLockNode * fln;
  7499.                                 LONG error;
  7500.  
  7501.                                 SafeObtainSemaphoreShared((struct SignalSemaphore *)SambaSemaphore);
  7502.  
  7503.                                 SHOWMSG("checking for possible lock collision");
  7504.  
  7505.                                 error = FindFileLockNodeByFileHandle(fileHandle,&fln);
  7506.                                 if(error == OK)
  7507.                                 {
  7508.                                     if(fln != NULL)
  7509.                                     {
  7510.                                         struct LockedRegionNode * lrn;
  7511.                                         BOOL shared;
  7512.  
  7513.                                         SHOWMSG("somebody has locked this file");
  7514.  
  7515.                                         shared = (BOOL)(l->l_type == F_RDLCK);
  7516.  
  7517.                                         lrn = FindCollidingRegion(fln,start,start+len-1,shared);
  7518.                                         if(lrn != NULL)
  7519.                                         {
  7520.                                             SHOWMSG("there is a possible lock collision");
  7521.  
  7522.                                             l->l_type    = (lrn->lrn_Shared ? F_RDLCK : F_WRLCK);
  7523.                                             l->l_whence    = SEEK_SET;
  7524.                                             l->l_start    = lrn->lrn_Start;
  7525.                                             l->l_len    = lrn->lrn_Stop - lrn->lrn_Start + 1;
  7526.                                             l->l_pid    = lrn->lrn_Owner;
  7527.                                         }
  7528.                                         else
  7529.                                         {
  7530.                                             SHOWMSG("there is no lock collision");
  7531.  
  7532.                                             l->l_type = F_UNLCK;
  7533.                                         }
  7534.                                     }
  7535.                                     else
  7536.                                     {
  7537.                                         SHOWMSG("nobody has locked this file");
  7538.  
  7539.                                         l->l_type = F_UNLCK;
  7540.                                     }
  7541.  
  7542.                                     result = OK;
  7543.                                 }
  7544.                                 else
  7545.                                 {
  7546.                                     SetIoErr(error);
  7547.  
  7548.                                     MapIoErrToErrno();
  7549.                                 }
  7550.  
  7551.                                 ReleaseSemaphore((struct SignalSemaphore *)SambaSemaphore);
  7552.                             }
  7553.                         }
  7554.                         else
  7555.                         {
  7556.                             SHOWMSG("zero length lock/unlock");
  7557.                             result = OK;
  7558.                         }
  7559.                     }
  7560.                     else
  7561.                     {
  7562.                         SHOWMSG("invalid start/len");
  7563.                         SHOWVALUE(start);
  7564.                         SHOWVALUE(len);
  7565.                         errno = EINVAL;
  7566.                     }
  7567.                 }
  7568.                 else
  7569.                 {
  7570.                     SHOWMSG("couldn't determine start/len");
  7571.                     MapIoErrToErrno();
  7572.                 }
  7573.             }
  7574.             else
  7575.             {
  7576.                 SHOWMSG("couldn't get the bookkeeping memory needed");
  7577.                 MapIoErrToErrno();
  7578.             }
  7579.  
  7580.             DeleteFileLockNode(fln);
  7581.             DeleteLockedRegionNode(lrn);
  7582.         }
  7583.         else
  7584.         {
  7585.             SHOWMSG("invalid lock type or seek offset");
  7586.             SHOWVALUE(l->l_type);
  7587.             SHOWVALUE(l->l_whence);
  7588.             errno = EINVAL;
  7589.         }
  7590.     }
  7591.     else
  7592.     {
  7593.         SHOWMSG("no flock or no ufb");
  7594.         SHOWVALUE(l);
  7595.         SHOWVALUE(ufb);
  7596.  
  7597.         errno = EINVAL;
  7598.     }
  7599.  
  7600.     RETURN(result);
  7601.     return(result);
  7602. }
  7603.  
  7604. int
  7605. amiga_fcntl(int fd,int cmd,unsigned long arg)
  7606. {
  7607.     struct UFB * ufb;
  7608.     struct flock * l;
  7609.     int result = ERROR;
  7610.  
  7611.     chkabort();
  7612.  
  7613.     ENTER();
  7614.  
  7615.     /* Don't try to lock data in a socket... */
  7616.     ufb = chkufb(fd);
  7617.     if(ufb == NULL || FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7618.         ufb = NULL;
  7619.  
  7620.     l = (struct flock *)arg;
  7621.  
  7622.     switch(cmd)
  7623.     {
  7624.         /* Get the first lock that blocks the lock description pointed to
  7625.          * by the third argument, arg, taken as a pointer to a struct
  7626.          * flock (see above).  The information retrieved overwrites the
  7627.          * information passed to fcntl in the flock structure.  If no
  7628.          * lock is found that would prevent this lock from being created,
  7629.          * the structure is left unchanged by this function call except
  7630.          * for the lock type which is set to F_UNLCK.
  7631.          */
  7632.         case F_GETLK:
  7633.  
  7634.             SHOWMSG("F_GETLK");
  7635.             result = HandleFileLocking(cmd,l,ufb);
  7636.             break;
  7637.  
  7638.         /* Set or clear a file segment lock according to the lock de-
  7639.          * scription pointed to by the third argument, arg, taken as a
  7640.          * pointer to a struct flock (see above).    F_SETLK is used to es-
  7641.          * tablish shared (or read) locks (F_RDLCK) or exclusive (or
  7642.          * write) locks, (F_WRLCK), as well as remove either type of lock
  7643.          * (F_UNLCK). If a shared or exclusive lock cannot be set, fcntl
  7644.          * returns immediately with EACCES.
  7645.          */
  7646.         case F_SETLK:
  7647.  
  7648.             SHOWMSG("F_SETLK");
  7649.             result = HandleFileLocking(cmd,l,ufb);
  7650.             break;
  7651.  
  7652.         /* This command is the same as F_SETLK except that if a shared or
  7653.          * exclusive lock is blocked by other locks, the process waits
  7654.          * until the request can be satisfied.  If a signal that is to be
  7655.          * caught is received while fcntl is waiting for a region, the
  7656.          * fcntl will be interrupted if the signal handler has not speci-
  7657.          * fied the SA_RESTART (see sigaction(2)).
  7658.          */
  7659.         case F_SETLKW:
  7660.  
  7661.             SHOWMSG("F_SETLKW");
  7662.             result = HandleFileLocking(cmd,l,ufb);
  7663.             break;
  7664.  
  7665.         /* Get descriptor status flags, as described below (arg is ig-
  7666.          * noted).
  7667.          */
  7668.         case F_GETFL:
  7669.  
  7670.             SHOWMSG("F_GETFL");
  7671.             result = IsDescriptorNonblocking(fd) ? O_NONBLOCK : 0;
  7672.             break;
  7673.  
  7674.         /* Set descriptor status flags to arg. */
  7675.         case F_SETFL:
  7676.  
  7677.             SHOWMSG("F_SETFL");
  7678.             if(FLAG_IS_SET(arg,O_NONBLOCK))
  7679.                 BlockDescriptor(fd);
  7680.             else
  7681.                 UnblockDescriptor(fd);
  7682.  
  7683.             result = OK;
  7684.             break;
  7685.  
  7686.         default:
  7687.  
  7688.             D(("Unknown command %ld",cmd));
  7689.             errno = ENOSYS;
  7690.             break;
  7691.     }
  7692.  
  7693.     RETURN(result);
  7694.     return(result);
  7695. }
  7696.  
  7697. /******************************************************************************/
  7698.  
  7699. int
  7700. amiga_fgetc(FILE *in)
  7701. {
  7702.     struct UFB * ufb;
  7703.     int result = ERROR;
  7704.  
  7705.     PUSH_ASSERTS();
  7706.  
  7707.     chkabort();
  7708.  
  7709.     ufb = chkufb(fileno(in));
  7710.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7711.     {
  7712.         UBYTE c;
  7713.  
  7714.         ENTER();
  7715.         SHOWMSG("input from socket");
  7716.  
  7717.         if(recv(ufb->ufbfh,&c,1,0) == 1)
  7718.             result = c;
  7719.     }
  7720.     else
  7721.     {
  7722.         result = fgetc(in);
  7723.     }
  7724.  
  7725.     RETURN(result);
  7726.     POP();
  7727.     return(result);
  7728. }
  7729.  
  7730. char *
  7731. amiga_fgets(char *str,int n,FILE * in)
  7732. {
  7733.     struct UFB * ufb;
  7734.     char *result;
  7735.  
  7736.     ENTER();
  7737.  
  7738.     ufb = chkufb(fileno(in));
  7739.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7740.     {
  7741.         char *s = str;
  7742.         LONG rc;
  7743.         UBYTE c;
  7744.  
  7745.         SHOWMSG("input from socket");
  7746.         result = str;
  7747.  
  7748.         while(--n > 0)
  7749.         {
  7750.             chkabort();
  7751.  
  7752.             rc = recv(ufb->ufbfh,&c,1,0);
  7753.             if(rc == 1)
  7754.             {
  7755.                 (*str++) = c;
  7756.  
  7757.                 if(c == '\n')
  7758.                     break;
  7759.             }
  7760.             else
  7761.             {
  7762.                 /* End of stream or nothing read? */
  7763.                 if(rc < 0 || str == s)
  7764.                     result = NULL;
  7765.  
  7766.                 break;
  7767.             }
  7768.         }
  7769.  
  7770.         if(result != NULL)
  7771.             (*str) = '\0';
  7772.     }
  7773.     else
  7774.     {
  7775.         result = fgets(str,n,in);
  7776.     }
  7777.  
  7778.     RETURN(result);
  7779.     return(result);
  7780. }
  7781.  
  7782. int
  7783. amiga_fputs(const char *str,FILE *out)
  7784. {
  7785.     struct UFB * ufb;
  7786.     int result;
  7787.  
  7788.     chkabort();
  7789.  
  7790.     ENTER();
  7791.  
  7792.     ufb = chkufb(fileno(out));
  7793.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7794.     {
  7795.         SHOWMSG("output to socket");
  7796.  
  7797.         if(NOT STRING_IS_EMPTY(str))
  7798.             result = send(ufb->ufbfh,str,strlen(str),0);
  7799.         else
  7800.             result = OK;
  7801.  
  7802.         if(result == OK)
  7803.             result = send(ufb->ufbfh,"\n",1,0);
  7804.     }
  7805.     else
  7806.     {
  7807.         result = fputs(str,out);
  7808.     }
  7809.  
  7810.     RETURN(result);
  7811.     return(result);
  7812. }
  7813.  
  7814. int
  7815. amiga_puts(const char *str)
  7816. {
  7817.     int result;
  7818.  
  7819.     result = amiga_fputs(str,stdout);
  7820.  
  7821.     return(result);
  7822. }
  7823.  
  7824. int
  7825. amiga_vfprintf(FILE *out,const char *fmt,va_list args)
  7826. {
  7827.     struct UFB * ufb;
  7828.     int result;
  7829.  
  7830.     chkabort();
  7831.  
  7832.     ENTER();
  7833.  
  7834.     ufb = chkufb(fileno(out));
  7835.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7836.     {
  7837.         char buffer[1024];
  7838.  
  7839.         SHOWMSG("output to socket");
  7840.  
  7841.         vsnprintf(buffer,sizeof(buffer)-1,fmt,args);
  7842.         buffer[sizeof(buffer)-1] = '\0';
  7843.  
  7844.         if(NOT STRING_IS_EMPTY(buffer))
  7845.             result = send(ufb->ufbfh,buffer,strlen(buffer),0);
  7846.         else
  7847.             result = 0;
  7848.     }
  7849.     else
  7850.     {
  7851.         result = vfprintf(out,fmt,args);
  7852.     }
  7853.  
  7854.     RETURN(result);
  7855.     return(result);
  7856. }
  7857.  
  7858. int
  7859. amiga_fprintf(FILE *out,const char *fmt,...)
  7860. {
  7861.     va_list args;
  7862.     int result;
  7863.  
  7864.     va_start(args,fmt);
  7865.     result = amiga_vfprintf(out,fmt,args);
  7866.     va_end(args);
  7867.  
  7868.     return(result);
  7869. }
  7870.  
  7871. int
  7872. amiga_printf(const char *fmt,...)
  7873. {
  7874.     va_list args;
  7875.     int result;
  7876.  
  7877.     va_start(args,fmt);
  7878.     result = amiga_vfprintf(stdout,fmt,args);
  7879.     va_end(args);
  7880.  
  7881.     return(result);
  7882. }
  7883.  
  7884. size_t
  7885. amiga_fwrite(const void *data,size_t blockSize,size_t numBlocks,FILE *out)
  7886. {
  7887.     struct UFB * ufb;
  7888.     size_t result;
  7889.  
  7890.     chkabort();
  7891.  
  7892.     ENTER();
  7893.  
  7894.     ufb = chkufb(fileno(out));
  7895.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7896.     {
  7897.         SHOWMSG("output to socket");
  7898.  
  7899.         result = send(ufb->ufbfh,(APTR)data,blockSize * numBlocks,0);
  7900.         if(result > 0)
  7901.             result = (result/blockSize);
  7902.     }
  7903.     else
  7904.     {
  7905.         result = fwrite(data,blockSize,numBlocks,out);
  7906.     }
  7907.  
  7908.     RETURN(result);
  7909.     return(result);
  7910. }
  7911.  
  7912. size_t
  7913. amiga_fread(void *data,size_t blockSize,size_t numBlocks,FILE *in)
  7914. {
  7915.     struct UFB * ufb;
  7916.     size_t result;
  7917.  
  7918.     chkabort();
  7919.  
  7920.     ENTER();
  7921.  
  7922.     ufb = chkufb(fileno(in));
  7923.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7924.     {
  7925.         SHOWMSG("input from socket");
  7926.  
  7927.         result = recv(ufb->ufbfh,(APTR)data,blockSize * numBlocks,0);
  7928.         if(result > 0)
  7929.             result = (result/blockSize);
  7930.     }
  7931.     else
  7932.     {
  7933.         result = fread(data,blockSize,numBlocks,in);
  7934.     }
  7935.  
  7936.     RETURN(result);
  7937.     return(result);
  7938. }
  7939.  
  7940. int
  7941. amiga_fclose(FILE * stream)
  7942. {
  7943.     struct UFB * ufb;
  7944.     int result;
  7945.  
  7946.     chkabort();
  7947.  
  7948.     ENTER();
  7949.  
  7950.     ufb = chkufb(fileno(stream));
  7951.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7952.         result = OK;
  7953.     else
  7954.         result = fclose(stream);
  7955.  
  7956.     RETURN(result);
  7957.     return(result);
  7958. }
  7959.  
  7960. int
  7961. amiga_fflush(FILE * stream)
  7962. {
  7963.     struct UFB * ufb;
  7964.     int result;
  7965.  
  7966.     chkabort();
  7967.  
  7968.     ENTER();
  7969.  
  7970.     ufb = chkufb(fileno(stream));
  7971.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7972.         result = OK;
  7973.     else
  7974.         result = fflush(stream);
  7975.  
  7976.     RETURN(result);
  7977.     return(result);
  7978. }
  7979.  
  7980. int
  7981. amiga_fseek(FILE * stream,long int offset,int mode)
  7982. {
  7983.     struct UFB * ufb;
  7984.     int result;
  7985.  
  7986.     chkabort();
  7987.  
  7988.     ENTER();
  7989.  
  7990.     ufb = chkufb(fileno(stream));
  7991.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  7992.         result = OK;
  7993.     else
  7994.         result = fseek(stream,offset,mode);
  7995.  
  7996.     RETURN(result);
  7997.     return(result);
  7998. }
  7999.  
  8000. long int
  8001. amiga_ftell(FILE * stream)
  8002. {
  8003.     struct UFB * ufb;
  8004.     long int result;
  8005.  
  8006.     chkabort();
  8007.  
  8008.     ENTER();
  8009.  
  8010.     ufb = chkufb(fileno(stream));
  8011.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  8012.         result = 0;
  8013.     else
  8014.         result = ftell(stream);
  8015.  
  8016.     RETURN(result);
  8017.     return(result);
  8018. }
  8019.  
  8020. /******************************************************************************/
  8021.  
  8022. int
  8023. amiga_setvbuf(FILE *stream,char *buff,int type,size_t size)
  8024. {
  8025.     struct UFB * ufb;
  8026.     int result;
  8027.  
  8028.     chkabort();
  8029.  
  8030.     ENTER();
  8031.  
  8032.     ufb = chkufb(fileno(stream));
  8033.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  8034.         result = OK;
  8035.     else
  8036.         result = setvbuf(stream,buff,type,size);
  8037.  
  8038.     RETURN(result);
  8039.     return(result);
  8040. }
  8041.  
  8042. /******************************************************************************/
  8043.  
  8044. int
  8045. amiga_fputc(int c,FILE *stream)
  8046. {
  8047.     struct UFB * ufb;
  8048.     int result = ERROR;
  8049.  
  8050.     chkabort();
  8051.  
  8052.     ENTER();
  8053.  
  8054.     ufb = chkufb(fileno(stream));
  8055.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  8056.     {
  8057.         UBYTE oneByte = c;
  8058.  
  8059.         if(send(ufb->ufbfh,&oneByte,1,0) > 0)
  8060.             result = OK;
  8061.     }
  8062.     else
  8063.     {
  8064.         result = fputc(c,stream);
  8065.     }
  8066.  
  8067.     RETURN(result);
  8068.     return(result);
  8069. }
  8070.  
  8071. /******************************************************************************/
  8072.  
  8073. VOID
  8074. amiga_setbuf(FILE *stream,char *buffer)
  8075. {
  8076.     struct UFB * ufb;
  8077.  
  8078.     chkabort();
  8079.  
  8080.     ENTER();
  8081.  
  8082.     ufb = chkufb(fileno(stream));
  8083.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  8084.     {
  8085.         /* Do nothing */
  8086.     }
  8087.     else
  8088.     {
  8089.         setbuf(stream,buffer);
  8090.     }
  8091.  
  8092.     LEAVE();
  8093. }
  8094.  
  8095. /******************************************************************************/
  8096.  
  8097. int
  8098. amiga_recv(int fd,void *buff,size_t nbytes,int flags)
  8099. {
  8100.     struct UFB * ufb;
  8101.     int result = ERROR;
  8102.  
  8103.     ENTER();
  8104.  
  8105.     ufb = chkufb(fd);
  8106.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  8107.         result = recv(ufb->ufbfh,buff,nbytes,flags);
  8108.     else
  8109.         errno = EBADF;
  8110.  
  8111.     RETURN(result);
  8112.     return(result);
  8113. }
  8114.  
  8115. /******************************************************************************/
  8116.  
  8117. int
  8118. amiga_send(int fd,void *buff,size_t nbytes,int flags)
  8119. {
  8120.     struct UFB * ufb;
  8121.     int result = ERROR;
  8122.  
  8123.     ENTER();
  8124.  
  8125.     ufb = chkufb(fd);
  8126.     if(ufb != NULL && FLAG_IS_SET(ufb->ufbflg,UFB_IS_SOCKET))
  8127.         result = send(ufb->ufbfh,buff,nbytes,flags);
  8128.     else
  8129.         errno = EBADF;
  8130.  
  8131.     RETURN(result);
  8132.     return(result);
  8133. }
  8134.  
  8135. /******************************************************************************/
  8136.  
  8137. int
  8138. amiga_smbrun(char *cmd,char *outfile,BOOL shared)
  8139. {
  8140.     struct MangleInfo mi_cmd;
  8141.     struct MangleInfo mi_outfile;
  8142.     int result = ERROR;
  8143.  
  8144.     ENTER();
  8145.  
  8146.     ForbidDOS();
  8147.  
  8148.     if(outfile == NULL)
  8149.         outfile = "/dev/null";
  8150.  
  8151.     if(MangleName(&cmd,&mi_cmd) == OK)
  8152.     {
  8153.         if(MangleName(&outfile,&mi_outfile) == OK)
  8154.         {
  8155.             BPTR in;
  8156.  
  8157.             in = Open("NIL:",MODE_OLDFILE);
  8158.             if(in != ZERO)
  8159.             {
  8160.                 BPTR out;
  8161.  
  8162.                 out = Open(outfile,MODE_NEWFILE);
  8163.                 if(out != ZERO)
  8164.                 {
  8165.                     if(SystemTags(cmd,
  8166.                         SYS_Input,        in,
  8167.                         SYS_Output,        out,
  8168.                         SYS_UserShell,    TRUE,
  8169.                         NP_WindowPtr,    NULL,
  8170.                     TAG_DONE) != -1)
  8171.                     {
  8172.                         result = OK;
  8173.                     }
  8174.                     else
  8175.                     {
  8176.                         MapIoErrToErrno();
  8177.                     }
  8178.  
  8179.                     Close(out);
  8180.                 }
  8181.                 else
  8182.                 {
  8183.                     MapIoErrToErrno();
  8184.                 }
  8185.  
  8186.                 Close(in);
  8187.             }
  8188.             else
  8189.             {
  8190.                 MapIoErrToErrno();
  8191.             }
  8192.  
  8193.             UnmangleName(&outfile,&mi_outfile);
  8194.         }
  8195.  
  8196.         UnmangleName(&cmd,&mi_cmd);
  8197.     }
  8198.  
  8199.     PermitDOS();
  8200.  
  8201.     RETURN(result);
  8202.     return(result);
  8203. }
  8204.  
  8205. /******************************************************************************/
  8206.  
  8207. #define IFBSIZE 1024
  8208. #define max(a,b) ( (a) > (b) ? (a) : (b) )
  8209.  
  8210. int
  8211. amiga_get_interfaces(struct iface_struct * ifaces,int max_interfaces)
  8212. {
  8213.     struct ifreq * ifr_end;
  8214.     struct ifreq * ifr;
  8215.     struct ifconf * ifc;
  8216.     struct ifreq ifr_copy;
  8217.     int sockfd = -1;
  8218.     int result = -1;
  8219.     int total = 0;
  8220.     int len;
  8221.  
  8222.     /* Make room for the interface information. I hope
  8223.      * that 1024 bytes will be sufficient.
  8224.      */
  8225.     ifc = malloc(sizeof(*ifc) + IFBSIZE);
  8226.     if(ifc == NULL)
  8227.     {
  8228.         errno = ENOMEM;
  8229.         goto out;
  8230.     }
  8231.  
  8232.     sockfd = socket(AF_INET,SOCK_STREAM,0);
  8233.     if(sockfd < 0)
  8234.         goto out;
  8235.  
  8236.     /* Now attempt to copy the interface information into
  8237.      * the buffer. As of this writing, support for the
  8238.      * SIOCGIFCONF ioctl() action is undocumented in all
  8239.      * currently existing TCP/IP stacks. Nevertheless,
  8240.      * it appears to work.
  8241.      */
  8242.     ifc->ifc_len = IFBSIZE;
  8243.     ifc->ifc_buf = (char *)(ifc+1);
  8244.  
  8245.     if(IoctlSocket(sockfd,SIOCGIFCONF,(char *)ifc) != OK)
  8246.         goto out;
  8247.  
  8248.     len = ifc->ifc_len;
  8249.  
  8250.     ifr = (struct ifreq *)ifc->ifc_buf;
  8251.     ifr_end = (struct ifreq *)((char *)ifr + len);
  8252.  
  8253.     /* Now check each interface, extracting the interface
  8254.      * information.
  8255.      */
  8256.     while(ifr < ifr_end && total < max_interfaces)
  8257.     {
  8258.         ifr_copy = (*ifr);
  8259.  
  8260.         /* Try to obtain the address information. */
  8261.         if(IoctlSocket(sockfd,SIOCGIFADDR,(char *)&ifr_copy) == OK)
  8262.         {
  8263.             struct in_addr ipaddr;
  8264.  
  8265.             /* We need to remember this for later. */
  8266.             ipaddr = (*(struct sockaddr_in *)&ifr_copy.ifr_addr).sin_addr;
  8267.  
  8268.             /* And query the interface flags; in particular, we are interested
  8269.              * in whether this interface is currrently "up", i.e. "online".
  8270.              */
  8271.             if(IoctlSocket(sockfd,SIOCGIFFLAGS,(char *)&ifr_copy) == OK)
  8272.             {
  8273.                 if(ifr_copy.ifr_flags & IFF_UP)
  8274.                 {
  8275.                     /* And finally obtain the interface net mask. */
  8276.                     if(IoctlSocket(sockfd,SIOCGIFNETMASK,(char *)&ifr_copy) == OK)
  8277.                     {
  8278.                         struct in_addr nmask;
  8279.  
  8280.                         nmask = ((struct sockaddr_in *)&ifr_copy.ifr_addr)->sin_addr;
  8281.  
  8282.                         strncpy(ifaces[total].name, ifr_copy.ifr_name, sizeof(ifaces[total].name)-1);
  8283.                         ifaces[total].name[sizeof(ifaces[total].name)-1] = '\0';
  8284.  
  8285.                         ifaces[total].ip = ipaddr;
  8286.                         ifaces[total].netmask = nmask;
  8287.  
  8288.                         total++;
  8289.                     }
  8290.                 }
  8291.             }
  8292.         }
  8293.  
  8294.         len = max(sizeof(struct sockaddr),ifr->ifr_addr.sa_len);
  8295.         ifr = (struct ifreq *)(((char *)ifr) + sizeof(ifr->ifr_name) + len);
  8296.     }
  8297.  
  8298.     result = total;
  8299.  
  8300.  out:
  8301.  
  8302.     if(ifc != NULL)
  8303.         free(ifc);
  8304.  
  8305.     if(sockfd != -1)
  8306.         CloseSocket(sockfd);
  8307.  
  8308.     return(result);
  8309. }
  8310.  
  8311. /******************************************************************************/
  8312.  
  8313. FILE *
  8314. amiga_popen(const char * command,const char * mode)
  8315. {
  8316.     /* For now, nothing happens here. */
  8317.  
  8318.     errno = EPIPE;
  8319.  
  8320.     return(NULL);
  8321. }
  8322.  
  8323. int
  8324. amiga_pclose(FILE * fp)
  8325. {
  8326.     /* Almost twice as much happens here. */
  8327.     return(OK);
  8328. }
  8329.